<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>AnChen 的博客</title>
  
  <subtitle>一直向前就是进步</subtitle>
  <link href="/atom.xml" rel="self"/>
  
  <link href="http://yoursite.com/"/>
  <updated>2019-07-03T02:17:32.000Z</updated>
  <id>http://yoursite.com/</id>
  
  <author>
    <name>An Chen</name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title>http缓存探讨</title>
    <link href="http://yoursite.com/2019/06/14/http%E7%BC%93%E5%AD%98%E6%8E%A2%E8%AE%A8/"/>
    <id>http://yoursite.com/2019/06/14/http缓存探讨/</id>
    <published>2019-06-14T08:59:00.000Z</published>
    <updated>2019-07-03T02:17:32.000Z</updated>
    
    <content type="html"><![CDATA[<p>业务场景：最近报了个问题，就是有个项目迭代更新时，有部分用户报进入后会白屏，必须ctrl+F5强制刷新才可以拉到最新的。看了后发现白屏原因是因为用户在我更新后访问的html页面还是旧的页面，所以里面的js引用的是旧的js（md5后缀），而旧的js地址在我更新后会删除，所以404，页面显示白屏…</p><p>一开始我加了以下的代码：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"Cache-Control"</span> <span class="attr">content</span>=<span class="string">"no-cache, no-store, must-revalidate"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"Pragma"</span> <span class="attr">content</span>=<span class="string">"no-cache"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">meta</span> <span class="attr">http-equiv</span>=<span class="string">"Expires"</span> <span class="attr">content</span>=<span class="string">"0"</span>&gt;</span></span><br></pre></td></tr></table></figure><p>是的，无效，其实这段对不同的浏览器效果有差，不建议使用。</p><hr><h3 id="HTTP首部字段结构"><a href="#HTTP首部字段结构" class="headerlink" title="HTTP首部字段结构"></a>HTTP首部字段结构</h3><p>只列出部分</p><p>1.通用首部字段（请求报文和响应报文都会使用的头部）：</p><ul><li><p>Cache-Control：控制缓存的行为</p><p><a href="https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Cache-Control" target="_blank" rel="noopener">Cache-Control</a></p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">Cache-Control: max-age=<span class="tag">&lt;<span class="name">seconds</span>&gt;</span></span><br><span class="line">Cache-Control: max-age=<span class="tag">&lt;<span class="name">seconds</span>&gt;</span></span><br><span class="line">Cache-Control: max-stale[=<span class="tag">&lt;<span class="name">seconds</span>&gt;</span>]</span><br><span class="line">Cache-Control: min-fresh=<span class="tag">&lt;<span class="name">seconds</span>&gt;</span></span><br><span class="line">Cache-control: no-cache ：强制向服务器进行验证（禁止强缓存，协商缓存可用）</span><br><span class="line">Cache-control: no-store ：禁止使用缓存</span><br><span class="line">Cache-control: no-transform</span><br><span class="line">Cache-control: only-if-cached：从缓存获取资源</span><br></pre></td></tr></table></figure></li></ul><ul><li>Date：创建报文的日期时间</li></ul><p>2.请求首部字段</p><ul><li>if-Modified-Since：比较资源的更新时间</li></ul><p>3.响应首部字段</p><ul><li>ETag：资源的匹配信息</li></ul><p>4.实体首部字段</p><ul><li>Expires：实体主体过期的日期时间</li><li>Last-Modified：资源的最后修改日期</li></ul><h3 id="浏览器缓存分类"><a href="#浏览器缓存分类" class="headerlink" title="浏览器缓存分类"></a>浏览器缓存分类</h3><blockquote><p>目前主流的浏览器缓存分为两类，强缓存和协商缓存，它们的匹配流程如下：</p><p>（1）浏览器发送请求前，根据请求头的expires和cache-control判断是否命中强缓存策略，如果命中，直接从缓存获取资源，并不会发送请求。如果没有命中，则进入下一步。</p><p>（2）没有命中强缓存规则，浏览器会发送请求，根据请求头的last-modified和etag判断是否命中协商缓存，如果命中，直接从缓存获取资源。如果没有命中，则进入下一步。</p><p>（3）如果前两步都没有命中，则直接从服务端获取资源。</p></blockquote><p><img src="https://anchen1204.github.io/2019/06/14/http%E7%BC%93%E5%AD%98%E6%8E%A2%E8%AE%A8/cache1.png" alt=""></p><p>发现新打开页面时Status Code都是200 （from disk cache）。然后在此页面上刷新就是304。</p><p><strong>强缓存</strong></p><p>从from disk cache得知，其实浏览器一直拿的自己的缓存，所以导致根本没有拉到我最新更新的文件，这时只有强制刷新才能拿到（200）。这个状态是强缓存的结果，有<code>expires/cache-control</code>控制：</p><blockquote><p>1.expires(http 1.0版有效)是绝对时间；是http1.0的功能。如果浏览器的时间没有超过这个expires的时间，代表缓存还有效，命中强缓存，直接从缓存读取资源。不过由于存在浏览器和服务端时间可能出现较大误差，所以在之后http1.1提出了cache-control。</p><p>2.cache-control的值是相对时间，当浏览器第一次请求资源的时候，会把response header的内容缓存下来。之后的请求会先从缓存检查该response header，通过第一次请求的date和cache-control计算出缓存有效时间。如果浏览器的时间没有超过这个缓存有效的时间，代表缓存还有效，命中强缓存，直接从缓存读取资源。</p><p>Expires用时刻来标识失效时间，不免收到时间同步的影响，而Cache-Control使用时间间隔很好的解决了这个问题。 但是 Cache-Control 是 HTTP1.1 才有的，不适用于 HTTP1.0，而 Expires 既适用于 HTTP1.0，也适用于 HTTP1.1，所以说在大多数情况下同时发送这两个头会是一个更好的选择，当客户端两种头都能解析的时候，会<strong>优先使用 Cache-Control</strong>。</p></blockquote><p>补充一下:Chrome在高版本更新了缓存策略,原来的<code>from cache</code>变成了<code>from disk cache(磁盘缓存)</code>和<code>from memory cache(内存缓存)</code>。</p><p><strong>协商缓存(弱缓存)</strong></p><p>后面在页面上刷新拿到的304，实际上就是协商缓存的结果。</p><blockquote><p>配置Last-Modified/ETag的情况下，浏览器再次访问统一URI的资源，还是<strong>会发送请求</strong>到服务器询问文件是否已经修改，如果没有，服务器会只发送一个304回给浏览器，告诉浏览器直接从自己本地的缓存取数据；如果修改过那就整个数据重新发给浏览器；</p><p>你可能会觉得使用Last-Modified已经足以让浏览器知道本地的缓存副本是否足够新，为什么还需要Etag（实体标识）呢？HTTP1.1中Etag的出现主要是为了解决几个Last-Modified比较难解决的问题：</p><ol><li>Last-Modified标注的最后修改只能精确到<strong>秒级</strong>，如果某些文件在1秒钟以内，被修改多次的话，它将不能准确标注文件的新鲜度</li><li>如果某些文件会被定期生成，当有时内容并没有任何变化，但Last-Modified却改变了，导致文件没法使用缓存</li><li>有可能存在服务器没有准确获取文件修改时间，或者与代理服务器时间不一致等情形</li></ol><p>Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符，能够更加准确的控制缓存。Last-Modified与ETag是可以一起使用的，<strong>服务器会优先验证ETag</strong>，一致的情况下，才会继续比对Last-Modified，最后才决定是否返回304。Etag的服务器生成规则和强弱Etag的相关内容可以参考，《<a href="http://www.hudong.com/wiki/Etag" target="_blank" rel="noopener">互动百科-Etag</a>》和《<a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html" target="_blank" rel="noopener">HTTP Header definition</a>》</p></blockquote><blockquote><p>一般情况下，使用Cache-Control/Expires会配合Last-Modified/ETag一起使用，因为即使服务器设置缓存时间, 当用户点击“刷新”按钮时，浏览器会忽略缓存继续向服务器发送请求，这时Last-Modified/ETag将能够很好利用304，从而减少响应开销。</p></blockquote><p><strong>强缓存与协商缓存总结</strong></p><ol><li>强缓存阶段：先在本地查找该资源，如果发现该资源，并且其他限制也没有问题(比如:缓存有效时间)，就命中强缓存，返回200，直接使用强缓存，并且不会发送请求到服务器。（不对服务器发送请求）</li><li>弱缓存阶段：在本地缓存中找到该资源，发送一个http请求到服务器，服务器判断这个资源没有被改动过，则返回304，让浏览器使用该资源。（需要发送请求，验证是否可以使用本地缓存）</li><li>缓存失败阶段(重新请求)：当服务器发现该资源被修改过，或者在本地没有找到该缓存资源，服务器则返回该资源的数据。</li></ol><p>新建页面会先验证强缓存。</p><p>F5刷新导致强缓存失效。</p><p>ctrl+F5 所有缓存都失效。</p><p><strong>启发式缓存</strong></p><p>那么问题肯定是缓存造成的，为什么会出现这样的情况，就可以排查了。</p><p>发现第一次访问200 （from disk cache）的时候，请求头（Request Header）显示<code>Provisional header are shown</code>,相关信息不能查看。</p><p>有这个提示通常可能的情况是：</p><blockquote><ol><li>跨域，请求被浏览器拦截</li><li>请求被浏览器插件拦截</li><li>服务器出错或者超时，没有真正的返回</li><li>强缓存from disk cache或者from memory cache，此时也不会显示</li></ol></blockquote><p>这里就是第4种情况。请求头不带缓存相关字段，如果本地缓存版本有效，从缓存读取，不发请求，并显示个假请求头。</p><p>找到了一篇很受启发的文章：</p><p><a href="https://zhuanlan.zhihu.com/p/24467558" target="_blank" rel="noopener">【腾讯Bugly干货分享】彻底弄懂 Http 缓存机制 - 基于缓存策略三要素分解法</a></p><p>因为这里的请求头不带缓存相关字段，所以使用了缓存过期的策略，影响要素在于：在没有任何缓存相关字段的情况下，客户端计算响应头中2个时间字段Date和Last-Modified之间的差值，取该值的10%作为缓存过期周期。这段时间内会直接使用本地缓存数据而不会再去请求服务器（强制请求除外），缓存过期后，会再次请求服务端，并携带上 Last-Modified 指定的时间去服务器对比并根据服务端的响应状态决定是否要从本地加载缓存数据。</p><p><img src="https://pic4.zhimg.com/80/v2-1494676f664d40eff41e37bfbc522323_hd.png" alt=""></p><p>接着对比实际的返回头发现，问题果然出现在Last-Modified。在这个问题页面里，Last-Modified的这个时间值竟然不会变，似乎一直停留在了5月份。</p><p>后来发现似乎是gitlab ci构建镜像输出的生产文件时间有误，经过修正又恢复了正常。。。</p><p><strong>cookie和session</strong></p><p>cookie和session都是为了弥补http协议的无状态特性，对server端来说无法知道两次http请求是否来自同一个用户，利用cookie和session就可以让用户只登录一次，server就知道某个请求是否需用重新登录。</p><ol><li><p>cookie：客户端第一次正常访问服务器，服务器在response headers中返回与用户信息相关的cookie，客户端收到后把cookie保存在本地，下次再发请求时会在request headers中带上这个cookie，服务器收到这个cookie就知道用户状态了。cookie可以设置过期时间，默认值是-1，表示关闭浏览器时cookie就会失效，值为0时表示立马失效，相当于删除cookie（cookie没有删除的方法），服务器和客户端都可以设置cookie，但不可以操作另一个域名下的cookie。</p></li><li><p>session: 客户端第一次正常访问服务器，服务器生成一个sessionid来标识用户并保存用户信息（服务器有一个专门的地方来保存所有用户的sessionId），在response headers中作为cookie的一个值返回，客户端收到后把cookie保存在本地，下次再发请求时会在request headers中带上这个sessionId，服务器通过查找这个sessionId就知道用户状态了，并更新sessionId的最后访问时间。sessionId也会可以设置失效时间，比如如果60分钟内某个session都没有被更新，服务器就会删除这个它。</p></li></ol><p>所有，cookie是保存在客户端，session是存在服务器，session依赖于cookie。</p><hr><p>备注：<a href="https://docs.gitlab.com/ee/ci/yaml/README.html#git-strategy" target="_blank" rel="noopener">https://docs.gitlab.com/ee/ci/yaml/README.html#git-strategy</a>(强制gitlab ci时候每次都通过clone来获取代码，以确保拿到代码时间戳是构建开始时间):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">variables:</span><br><span class="line">  GIT_STRATEGY: clone</span><br></pre></td></tr></table></figure><p>其他参考：</p><p><a href="https://book.douban.com/subject/25863515/" target="_blank" rel="noopener">《图解HTTP》</a></p><p><a href="http://www.alloyteam.com/2012/03/web-cache-2-browser-cache/" target="_blank" rel="noopener">Web缓存机制系列</a></p><p><a href="https://juejin.im/post/5bf3c28ee51d4514df5b7625" target="_blank" rel="noopener">浅聊HTTP缓存 (HTTP Cache)</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;业务场景：最近报了个问题，就是有个项目迭代更新时，有部分用户报进入后会白屏，必须ctrl+F5强制刷新才可以拉到最新的。看了后发现白屏原因是因为用户在我更新后访问的html页面还是旧的页面，所以里面的js引用的是旧的js（md5后缀），而旧的js地址在我更新后会删除，所以4
      
    
    </summary>
    
    
      <category term="web" scheme="http://yoursite.com/tags/web/"/>
    
  </entry>
  
  <entry>
    <title>phaser入门</title>
    <link href="http://yoursite.com/2019/02/13/phaser%E5%85%A5%E9%97%A8/"/>
    <id>http://yoursite.com/2019/02/13/phaser入门/</id>
    <published>2019-02-13T06:30:00.000Z</published>
    <updated>2019-07-03T08:20:41.000Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://segmentfault.com/a/1190000009212221" target="_blank" rel="noopener">https://segmentfault.com/a/1190000009212221</a></p><p>用这个例子来做修改，修改的功能点如下，也是原作者留白的内容</p><ul><li><p>游戏中字体的更换</p></li><li><p>地面应该和小恐龙底部持平，而非屏幕底部，如何实现？</p></li><li><p>现在三种苹果和炸弹的出现概率是随机的，如何调整它们各自的出现概率？</p></li><li><p>现在苹果和炸弹出现的时间间隔是固定的，如何随着游戏进行加快节奏？</p></li><li><p>如何调整游戏难度梯度？</p></li><li><p>现在炸弹和苹果有可能会相邻出现，导致很难接到苹果而不碰到炸弹，如何避免？</p></li></ul><p><strong>游戏中字体的更换 </strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">title = game.add.text(game.world.centerX, game.world.height * <span class="number">0.25</span>, <span class="string">'0'</span>, &#123;</span><br><span class="line">                   font:<span class="string">'bold 60px Helvetica'</span>,</span><br><span class="line">                   fill:<span class="string">'#f2bb15'</span></span><br><span class="line">               &#125;);</span><br></pre></td></tr></table></figure><p><strong>地面应该和小恐龙底部持平，而非屏幕底部，如何实现？</strong></p><p>首先应该实现一个地板，</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">game.load.image(<span class="string">'ground'</span>, <span class="string">'//peiwan.bs2dlssl.huanjuyun.com/da38bffbb5954779887ad623c5cc2b10.png'</span>);<span class="comment">//预先加载地板的图片</span></span><br></pre></td></tr></table></figure><p>像加man一样加到场景中：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//地面 </span></span><br><span class="line">platforms =game.add.sprite(game.world.centerX, game.world.height * <span class="number">0.84</span> , <span class="string">'ground'</span>);</span><br><span class="line"><span class="keyword">var</span> groundImg = game.cache.getImage(<span class="string">'ground'</span>);</span><br><span class="line">platforms.width = game.world.width;</span><br><span class="line">platforms.height = platforms.width/groundImg.width * groundImg.height;</span><br><span class="line">platforms.anchor.setTo(<span class="number">0.5</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p>注释掉苹果与游戏边缘碰撞的代码，因为现在要变成苹果与地板的碰撞。这里还是用物理碰撞overlap。</p><p>所以要碰撞的两个物体都要加入物理系统，才能开启物体的物理特性，苹果已经加入了，现在加入地板的：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">game.physics.enable(platforms);</span><br></pre></td></tr></table></figure><p>开启物理特性后的对象后就有了body属性，我们这里要用到body的allowGravity（是否启用重力效果）；如果不用的话默认是true，它放在游戏里后就会自动下落直到出边界，很明显我们不是要这样的效果，地板是不用下沉的。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">platforms.body.allowGravity = <span class="literal">false</span>;</span><br></pre></td></tr></table></figure><p>最后跟man和apples一样检测碰撞并且执行碰撞后的函数就可以了</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">game.physics.arcade.overlap(platforms,apples,failgame,<span class="literal">null</span> ,<span class="keyword">this</span>);</span><br><span class="line">...</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">failgame</span>(<span class="params">platforms, apple</span>)</span>&#123;</span><br><span class="line">             apple.kill();</span><br><span class="line">             <span class="keyword">if</span> (apple.type !== <span class="string">'bomb'</span>) game.state.start(<span class="string">'over'</span>, <span class="literal">true</span>, <span class="literal">false</span>, score);</span><br><span class="line">        &#125;</span><br></pre></td></tr></table></figure><p>在设置地板的过程中，开了debug，敲好用：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.render=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    game.debug.body(platforms);           </span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure><p>拓展一下，如果我的苹果掉落不需要消失，而是停留在地面上呢？</p><p>首先要知道，在Arcade物理引擎中，碰撞检测主要用到两个函数，一个是collide，还有一个是overlap。</p><p>collide方法与overlap的区别在于collide会影响两个要检测的对象之间的物理状态，比如使用collide函数去检测两个物体，如果物体碰撞了，那么这两个物体之间就会有力的相互作用，可能其中一个会被另一个弹开，或者两个之间相互弹开。</p><p>但如果使用overlap方法的话，则只会检测两个物体是否已经碰撞了，或者说已经重叠了，并不会产生物理作用。</p><p>所以如果是这样的情况，我们要使用collide来进行碰撞检测：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">game.physics.arcade.collide(platforms, apples);</span><br></pre></td></tr></table></figure><p>同时，地板需要在加一个属性：immovable,不设置的话，地板会被苹果砸下去</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">platforms.body.immovable = <span class="literal">true</span>;<span class="comment">//设置是否固定不动</span></span><br></pre></td></tr></table></figure><p><strong>现在三种苹果和炸弹的出现概率是随机的，如何调整它们各自的出现概率？</strong></p><p>首先看原来的代码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 添加苹果组</span></span><br><span class="line"><span class="keyword">var</span> apples = game.add.group();</span><br><span class="line"><span class="comment">// 苹果类型</span></span><br><span class="line"><span class="keyword">var</span> appleTypes = [<span class="string">'green'</span>, <span class="string">'red'</span>, <span class="string">'yellow'</span>];</span><br><span class="line"><span class="keyword">var</span> appleTimer = game.time.create(<span class="literal">true</span>);</span><br><span class="line">appleTimer.loop(<span class="number">1000</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">var</span> x = <span class="built_in">Math</span>.random() * game.world.width;</span><br><span class="line">    <span class="keyword">var</span> y = <span class="built_in">Math</span>.random() * game.world.height;</span><br><span class="line">    <span class="keyword">var</span> type = appleTypes[<span class="built_in">Math</span>.floor(<span class="built_in">Math</span>.random() * appleTypes.length)];</span><br><span class="line">    apples.create(x, y, type);</span><br><span class="line">&#125;);</span><br><span class="line">appleTimer.start()</span><br></pre></td></tr></table></figure><p><code>add</code>和<code>loop</code>两个方法，分别对应setTimeout和setInterval，效果是每隔1秒就会在屏幕随机位置出现一个苹果了，而且种类是随机的。</p><p>可以看出，掉落的种类主要是这一句：</p><p><code>var type = appleTypes[Math.floor(Math.random() * appleTypes.length)]</code>。</p><p>简单来说就是[0,1,2,3] 这个数组随机选一个随机数，现在我们要求的是给他们加权重，来选择随机数.</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">weightedRand</span>(<span class="params">spec</span>) </span>&#123;</span><br><span class="line">  <span class="keyword">var</span> i, sum=<span class="number">0</span>, r=<span class="built_in">Math</span>.random();</span><br><span class="line">  <span class="keyword">for</span> (i <span class="keyword">in</span> spec) &#123;</span><br><span class="line">    sum += spec[i];</span><br><span class="line">    <span class="keyword">if</span> (r &lt;= sum) <span class="keyword">return</span> i;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">weightedRand(&#123;<span class="number">0</span>:<span class="number">0.4</span>, <span class="number">1</span>:<span class="number">0.2</span>, <span class="number">2</span>:<span class="number">0.1</span>,<span class="number">3</span>:<span class="number">0.3</span>&#125;);</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> type = appleTypes[weightedRand(&#123;<span class="number">0</span>:<span class="number">0.4</span>, <span class="number">1</span>:<span class="number">0.2</span>, <span class="number">2</span>:<span class="number">0.1</span>,<span class="number">3</span>:<span class="number">0.3</span>&#125;)];</span><br></pre></td></tr></table></figure><p><strong>现在苹果和炸弹出现的时间间隔是固定的，如何随着游戏进行加快节奏？</strong></p><p>原代码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">appleTimer.loop(<span class="number">1000</span>, <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;&#125;)</span><br></pre></td></tr></table></figure><p>所以我们首先要想获取游戏时间，然后让时间间隔随着游戏时间的增加来减少。</p><p><code>this.game.time.totalElapsedSeconds()</code>可以计算从打开页面到现在的时间。<a href="https://www.phaser-china.com/example-detail-586.html" target="_blank" rel="noopener">demo</a></p><p>我想了下觉得，无限循环loop有些不适用,改成<code>game.time.events.add(loopTime, appleDown,this);</code></p><p>苹果/炸弹的添加用个appleDown函数包起来，定义一个变量appleTimeInterval来记录游戏时间,根据游戏时间修改loopTime（间隔）。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">appleDown</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    ...</span><br><span class="line">        <span class="comment">/*以下为新增*/</span></span><br><span class="line">       appleTimeInterval= game.time.totalElapsedSeconds();</span><br><span class="line">       <span class="keyword">if</span>(appleTimeInterval&gt;<span class="number">10</span> &amp;&amp; appleTimeInterval&lt;<span class="number">20</span>)&#123;</span><br><span class="line">            loopTime = <span class="number">1000</span>;</span><br><span class="line">        &#125;<span class="keyword">else</span> <span class="keyword">if</span>(appleTimeInterval&gt;<span class="number">20</span>)&#123;</span><br><span class="line">             loopTime = <span class="number">500</span>;</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="built_in">console</span>.log(loopTime)</span><br><span class="line">        game.time.events.add(loopTime, appleDown,<span class="keyword">this</span>); </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>如何调整游戏难度梯度？</strong></p><p>这比较笼统了，可以设定炸弹出现的频率或者缩短apple的时间间隔？</p><p><strong>现在炸弹和苹果有可能会相邻出现，导致很难接到苹果而不碰到炸弹，如何避免？</strong></p><p>这个问题看这段:</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> x = <span class="built_in">Math</span>.random() * game.world.width;</span><br><span class="line"><span class="keyword">var</span> type = appleTypes[weightedRand(&#123;<span class="number">0</span>:<span class="number">0.4</span>, <span class="number">1</span>:<span class="number">0.2</span>, <span class="number">2</span>:<span class="number">0.1</span>,<span class="number">3</span>:<span class="number">0.3</span>&#125;)];              </span><br><span class="line"><span class="keyword">var</span> apple = apples.create(x, <span class="number">0</span>, type);</span><br></pre></td></tr></table></figure><p>所以只要对比x的值，如果炸弹的x值跟上一个苹果的值太接近，我们就重新生成x的值：定义一个用来保存上一个x值的变量<code>lastAppleX</code>，当生成是炸弹时，才需要进行对比。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> appleWidth = game.world.width / <span class="number">8</span>;</span><br><span class="line"><span class="keyword">var</span> x = <span class="built_in">Math</span>.random() * game.world.width;</span><br><span class="line"><span class="keyword">var</span> type = appleTypes[weightedRand(&#123; <span class="number">0</span>: <span class="number">0.4</span>, <span class="number">1</span>: <span class="number">0.2</span>, <span class="number">2</span>: <span class="number">0.1</span>, <span class="number">3</span>: <span class="number">0.3</span> &#125;)];</span><br><span class="line"></span><br><span class="line">  <span class="keyword">if</span> (type == <span class="string">'bomb'</span>) &#123;</span><br><span class="line">      <span class="keyword">var</span> twoDistance = <span class="built_in">Math</span>.abs(lastAppleX - x);</span><br><span class="line">      <span class="built_in">console</span>.log(<span class="string">'间隔:'</span> + twoDistance)</span><br><span class="line">      <span class="keyword">if</span> (twoDistance &lt; appleWidth) &#123;</span><br><span class="line">          <span class="built_in">console</span>.log(<span class="string">'间隔太小'</span>)</span><br><span class="line">          appleDown();</span><br><span class="line">          <span class="keyword">return</span>;</span><br><span class="line">      &#125; </span><br><span class="line">    <span class="keyword">var</span> apple = apples.create(x, <span class="number">0</span>, type);</span><br><span class="line">    lastAppleX = x; <span class="comment">//记录上一个x                   </span></span><br><span class="line">    apple.type = type;</span><br></pre></td></tr></table></figure><p>写到这里我又想起，如果是上一个是炸弹，然后是苹果呢？所以还要记录下type,并修改当本次与上次掉落不同东西才去对比：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span> (type !== lastType) &#123;</span><br><span class="line">   <span class="built_in">console</span>.log(<span class="string">'different type'</span>)</span><br><span class="line">   <span class="keyword">var</span> twoDistance = <span class="built_in">Math</span>.abs(lastAppleX - x);</span><br><span class="line">   <span class="built_in">console</span>.log(<span class="string">'间隔:'</span> + twoDistance)</span><br><span class="line">   <span class="keyword">if</span> (twoDistance &lt; appleWidth) &#123;</span><br><span class="line">       <span class="built_in">console</span>.log(<span class="string">'间隔太小'</span>)</span><br><span class="line">       appleDown();</span><br><span class="line">       <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">var</span> apple = apples.create(x, <span class="number">0</span>, type);</span><br><span class="line">lastAppleX = x; <span class="comment">//记录上一个x                   </span></span><br><span class="line">apple.type = type;</span><br><span class="line">lastType = apple.type;<span class="comment">//记录上一个type</span></span><br></pre></td></tr></table></figure><p>至此也就完成了原作者留白的功能点。但是如果要用到实际的项目中，我们还是可以再拓展。</p><p><strong>运营活动中可能还需要这个游戏做些什么呢？</strong></p><ol><li><p>派券</p><p>根据最后玩的分数，派出不同的券，假设50分以下为“30-5”优惠券，50-100分为“30-10”优惠券，100分以上是“20-10”优惠券。</p><p>这里涉及几个必须的点：</p><ul><li>控制数量/成本,假设我有“30-5”的券20张，”30-10“的券10张，”20-10”的券5张；</li><li>控制设备防刷，假定每个人每台设备一天只能玩一次；</li></ul></li><li><p>分享</p><p>这几乎是必然有的，微信分享本人的分数到朋友圈或者微信好友</p></li><li><p>… </p></li></ol><p>1、2点涉及到游戏的over状态，取score值。根据score来操作即可。</p><p>控制设备的在游戏的preload开始场景，可以在这里进行判断，如果不符合则加载另外的提示，有时候也需要在over状态进行提示，可能用户不在乎领券只是想玩一下。</p><p>分享的可以有一个静态h5来替换游戏地址，上面显示用户分数。</p><hr><p>修改后代码地址：<br><a href="https://github.com/anchen1204/game/blob/master/pharser-apple-example1/demo/game.js" target="_blank" rel="noopener">https://github.com/anchen1204/game/blob/master/pharser-apple-example1/demo/game.js</a></p><p>参考:</p><p><a href="https://www.phaser-china.com/example.html" target="_blank" rel="noopener">https://www.phaser-china.com/example.html</a></p><p><a href="https://ryangun.github.io/2018/01/04/Phaser%E5%9F%BA%E7%A1%80%E7%AF%87%E4%B8%8A/" target="_blank" rel="noopener">https://ryangun.github.io/2018/01/04/Phaser%E5%9F%BA%E7%A1%80%E7%AF%87%E4%B8%8A/</a>  </p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;&lt;a href=&quot;https://segmentfault.com/a/1190000009212221&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://segmentfault.com/a/1190000009212221&lt;/a&gt;&lt;/p&gt;

      
    
    </summary>
    
    
      <category term="其他框架" scheme="http://yoursite.com/tags/%E5%85%B6%E4%BB%96%E6%A1%86%E6%9E%B6/"/>
    
  </entry>
  
  <entry>
    <title>零碎归纳</title>
    <link href="http://yoursite.com/2018/12/04/learn-2/"/>
    <id>http://yoursite.com/2018/12/04/learn-2/</id>
    <published>2018-12-04T03:18:00.000Z</published>
    <updated>2020-03-29T14:08:39.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="工具"><a href="#工具" class="headerlink" title="工具"></a>工具</h2><h3 id="hexo迁移"><a href="#hexo迁移" class="headerlink" title="hexo迁移"></a>hexo迁移</h3><p>因为我的笔记本电脑最近瓦特了，所以不得不把博客迁出来，在这里做个记录，方便下次查找。 </p><ul><li><p>将原来的电脑上原有的hexo目录拷贝到新电脑，只需拷贝以下目录：</p><ul><li>_config.yml</li><li>package.json</li><li>scaffolds/</li><li>source/</li><li>themes/</li></ul></li><li><p>在新电脑安装hexo</p><p><code>npm install -g hexo</code></p></li><li><p>安装后进入hexo/目录</p></li><li><p>安装模块</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">npm install</span><br><span class="line">npm install hexo-deployer-git --save</span><br><span class="line">npm install hexo-generator-feed --save</span><br><span class="line">npm install hexo-generator-sitemap --save</span><br></pre></td></tr></table></figure></li><li><p>然后重新配置github</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">git config --global user.name &quot;YOUR NAME&quot;</span><br><span class="line">git config --global user.email &quot;YOUR EMAIL ADDRESS&quot;</span><br></pre></td></tr></table></figure><p><strong>Authenticating with GitHub from Git</strong></p><ul><li><p>在 Git Bash 下执行如下命令，生成 SSH key</p><p><code>ssh-keygen -t rsa -b 4096 -C &quot;your_email@example.com&quot;</code></p><p>email为自己的github账号，剩下的一路回车即可。</p></li><li><p>将 SSH key 添加到 ssh-agent</p><ul><li>在 Git Bash 下执行如下命令，开启 ssh-agent</li></ul><p><code>eval &quot;$(ssh-agent -s)&quot;</code></p><ul><li>将这个 SSH key 添加到 ssh-agent 里去</li></ul><p><code>ssh-add ~/.ssh/id_rsa</code></p></li><li><p>将 SSH key 添加到 Github 账户</p><ul><li>在 Git Bash 中将 SSH Key 拷贝出来：</li></ul><p><code>clip &lt; ~/.ssh/id_rsa.pub</code></p><p>此时，SSH Key 已经在我们的剪切板里了。然后登录 Github 帐号，依次点击自己的头像，<strong>Settings</strong>，<strong>SSH and GPG keys</strong>， <strong>Add SSH key</strong>， 在 <strong>Title</strong> 这里输入 Key 的label，比如 <code>your_name - PC</code>，然后在 Key 里面把 <strong>SSH Key</strong> 粘贴进去，点击 <strong>Add SSH key</strong> 大功告成。</p></li><li><p>测试 SSH 连接，在 Git Bash 中敲入</p></li></ul><p><code>ssh -T git@github.com</code></p></li><li><p>做完上面这些后 执行hexo deploy 大功告成</p></li><li><p>但是我还是报错，hexo error fatal httprequestexception encountered….</p><p>后来在<a href="https://github.com/hexojs/hexo/issues/3043" target="_blank" rel="noopener">https://github.com/hexojs/hexo/issues/3043</a> 这里找到解决方法</p><p>把repo的配置方式改一下，任何就可以了。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">deploy:</span><br><span class="line">  type: git</span><br><span class="line">  repo: git@github.com:anchen1204/anchen1204.github.io.git</span><br><span class="line">  branch: master</span><br></pre></td></tr></table></figure><p>以上方法结合了这两篇文章：</p><p><a href="https://blog.csdn.net/eternity1118_/article/details/71194395?ref=myread" target="_blank" rel="noopener">hexo：更换电脑，如何继续写博客</a></p><p><a href="http://lowrank.science/Hexo-Migration/" target="_blank" rel="noopener">多机更新 Hexo 博客</a></p></li></ul><h2 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h2><h3 id="Object-assign"><a href="#Object-assign" class="headerlink" title="Object.assign()"></a>Object.assign()</h3><p>语法：<code>Object.assign(target, ...sources );</code></p><p>参数：</p><p><em>target</em>：必需。可枚举属性复制到的对象。</p><p><em>…sources</em>：必需。从其中复制可枚举属性的对象。</p><p>实例：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> first = &#123; <span class="attr">name</span>: <span class="string">"Bob"</span> &#125;;</span><br><span class="line"><span class="keyword">var</span> last = &#123; <span class="attr">lastName</span>: <span class="string">"Smith"</span> &#125;;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> person = <span class="built_in">Object</span>.assign(first, last);</span><br><span class="line"><span class="built_in">console</span>.log(person);<span class="comment">//&#123; name: "Bob", lastName: "Smith" &#125;</span></span><br></pre></td></tr></table></figure><p>看阮一峰大神的<a href="http://es6.ruanyifeng.com/#docs/style#Map-%E7%BB%93%E6%9E%84" target="_blank" rel="noopener">ES6-编程风格</a> :</p><p>对象尽量静态化，一旦定义，就不得随意添加新的属性。如果添加属性不可避免，要使用<code>Object.assign</code>方法。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// bad</span></span><br><span class="line"><span class="keyword">const</span> a = &#123;&#125;;</span><br><span class="line">a.x = <span class="number">3</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">// if reshape unavoidable</span></span><br><span class="line"><span class="keyword">const</span> a = &#123;&#125;;</span><br><span class="line"><span class="built_in">Object</span>.assign(a, &#123; <span class="attr">x</span>: <span class="number">3</span> &#125;);</span><br><span class="line"></span><br><span class="line"><span class="comment">// good</span></span><br><span class="line"><span class="keyword">const</span> a = &#123; <span class="attr">x</span>: <span class="literal">null</span> &#125;;</span><br><span class="line">a.x = <span class="number">3</span>;</span><br></pre></td></tr></table></figure><h3 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h3><p>阅读(按左到右顺序)：    <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Using_promises" target="_blank" rel="noopener">使用 Promises</a>  <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="noopener">Promise</a> </p><p>这两天又看了一遍Promise的内容，觉得这个对象真的非常好用。</p><p>做个总结呗，其实在项目中已经快乐地用起来了，很方便。</p><p>它存在的意义？还不是因为javaScript是世界上最好的…不对，说错台词了，应该是javaScript是单线程语言。</p><p>我们经常为了解决这个问题，使用的是回调函数，俗称callback，为了达到异步执行。比如<code>setTimeout</code> ,比如AJAX异步操作。</p><p>具体介绍不表，可以看文档。直接说使用吧。</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>( <span class="function"><span class="keyword">function</span>(<span class="params">resolve, reject</span>) </span>&#123;...&#125; <span class="comment">/* executor */</span>  );</span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function">(<span class="params">resolve, reject</span>) =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Initial'</span>);</span><br><span class="line"></span><br><span class="line">    resolve();</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="keyword">throw</span> <span class="keyword">new</span> <span class="built_in">Error</span>(<span class="string">'Something failed'</span>);</span><br><span class="line">        </span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Do this'</span>);</span><br><span class="line">&#125;)</span><br><span class="line">.catch(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Do that'</span>);</span><br><span class="line">&#125;)</span><br><span class="line">.then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="string">'Do this whatever happened before'</span>);</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p><code>.then()</code>是链式调用，获取上一个Promise resolve返回的对象进行操作；</p><p><code>.catch()</code> 原理同then，但是是针对Promise 的reject返回的对象进行操作；</p><p>注意：在一个失败操作（即一个 <code>catch</code>）之后可以继续使用链式操作，即使链式中的一个动作失败之后还能有助于新的动作继续完成。</p><p>即链式调用不会因为其中一个环节失败(reject)而中断。</p><p>好用组合：</p><p><code>Promise.resolve()</code> &amp;<code>Promise.reject()</code></p><p>这两个是手动创建一个已经resolve或者reject的promise快捷方法。</p><p><code>Promise.race()</code> 和<code>Promise.all()</code></p><p>这两个用法一样，其实括号内都是多个Promise对象</p><p>但是不同的地方在于：</p><p><code>Promise.all(iterable)</code> 方法返回一个 <a href="https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Promise" target="_blank" rel="noopener"><code>Promise</code></a> 实例，此实例在 iterable参数内所有的 promise 都完成（resolved），或参数中不包含 promise 时回调完成（resolve）；<strong>如果参数中  <code>promise</code> 有一个失败（rejected），此实例回调失败（reject），失败原因的是第一个失败 <code>promise</code> 的结果。</strong></p><p><code>Promise.race(iterable)</code>方法返回一个 promise，<strong>一旦迭代器中的某个promise解决或拒绝，返回的 promise就会解决或拒绝。</strong></p><p>一句话，前者如果有一个失败，则之间返回第一个失败(catch里)；后者只会返回第一个处理的失败或者成功。</p><p>举个实际可能会使用的例子：</p><p>Promise.all是很适合来解决多个Promise是用于获取请求基本信息，比如app里的登陆信息，ticket，版本号，它们都获取成功后可以接着执行可能下一步的请求。。。</p><p>Promise.race很适合容错现象，比如接口超时：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//网络超时写法：Promise.race()</span></span><br><span class="line"><span class="keyword">let</span> promise1 = <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span>=&gt;</span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">'数据已返回'</span>;</span><br><span class="line">    &#125;,<span class="number">5000</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">let</span> promise2= <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">reject</span>=&gt;</span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span>=&gt;</span>&#123;</span><br><span class="line">        reject(<span class="string">'网络超时'</span>)</span><br><span class="line">    &#125;,<span class="number">4000</span>)</span><br><span class="line">&#125;)</span><br><span class="line"><span class="built_in">Promise</span>.race([promise1,promise2]).then(<span class="function"><span class="params">res</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;).catch(<span class="function"><span class="params">res</span>=&gt;</span>&#123;</span><br><span class="line">    <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;工具&quot;&gt;&lt;a href=&quot;#工具&quot; class=&quot;headerlink&quot; title=&quot;工具&quot;&gt;&lt;/a&gt;工具&lt;/h2&gt;&lt;h3 id=&quot;hexo迁移&quot;&gt;&lt;a href=&quot;#hexo迁移&quot; class=&quot;headerlink&quot; title=&quot;hexo迁移&quot;&gt;&lt;/a&gt;h
      
    
    </summary>
    
    
      <category term="前端零碎" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E9%9B%B6%E7%A2%8E/"/>
    
  </entry>
  
  <entry>
    <title>零碎归纳</title>
    <link href="http://yoursite.com/2018/08/13/learn-1/"/>
    <id>http://yoursite.com/2018/08/13/learn-1/</id>
    <published>2018-08-13T05:30:00.000Z</published>
    <updated>2020-03-29T14:08:13.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="JavaScript"><a href="#JavaScript" class="headerlink" title="JavaScript"></a>JavaScript</h2><h3 id="原型"><a href="#原型" class="headerlink" title="原型"></a>原型</h3><p>之前写过一个使用：<a href="https://anchen1204.github.io/2016/06/04/javascript%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%9E%8B/" target="_blank" rel="noopener">javascript对象和原型</a> ，虽然在那个项目里这么用了，其实还是一知半解，这几天重新翻了下《你不知道的JavaScript 上卷》</p><p>首先，Javascript是面向对象的语言，它没有类；</p><p><strong>翻出n久前做的一个笔记：</strong></p><ol><li>所有的函数对象都有一个prototype属性，这个属性引用了一个对象，就是原型（对象）；</li></ol><ol><li><p>普通对象的内部<code>_proto_</code>指向它构造函数的prototype，原型对象也是普通对象的一种；</p></li><li><p>原型对象主要用于继承，js在创建对象时，都有一个<code>_proto</code>的内置属性，用于指向创建它的函数对象的原型对象prototype</p></li><li><p>原型和原型链是js实现继承的一种模型，原型链的形成靠<code>_proto_</code>,而不是prototype;</p></li><li><p>能修改prototype指向的对象，为prototype赋予一个不同的对象，可以实现一种简单的继承；</p></li><li><p>访问一个对象的原型可以使用ES5中的<code>Object.getPrototype()</code>方法，或ES6中的<code>_proto_</code>属性</p><p>​</p></li></ol><p><strong>然后在chrome浏览器做一个试验</strong></p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/1791532867937_.pic.jpg" alt=""></p><ul><li><p>函数有一个特殊特性，所有的<strong>函数</strong>默认都会拥有一个prototype的公有且不可枚举的属性，它会指向另一个对象，通常称为这个函数的原型对象。就是说，<strong>User函数的原型可以通过User.prototype来访问</strong>。</p></li><li><p>打印了User.prototype可以看的原型对象默认有一个公有的属性，constructor，这个属性引用的是对象关联的函数，就是说这里 User.prototype.constructor === User;</p></li><li><p>此外，可以看到通过构造函数调用new User( )创建的对象u，也有一个.constructor属性，指向“创建这个对象的函数”，也就是a.constructor ===User;</p></li><li><p>构造函数：User函数其实是一个普通的函数，可是为什么它会认为是一个“构造函数”，原因是，在普通的函数前面加上new关键字后，就会把这个函数调用变成一个“构造函数调用”。new会劫持所有普通函数并用构造对象的形式来调用它。就是说<strong>函数不是构造函数，但是当且仅当使用new时，函数调用会变成“构造函数调用”</strong></p></li><li><p>普通对象的内部<code>_proto_</code>指向它构造函数的prototype，原型对象也是普通对象的一种,也就是说</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">u.__proto__===User.__proto__ <span class="comment">//true</span></span><br><span class="line">u.__proto__===User.prototype <span class="comment">//true</span></span><br><span class="line">u.prototype <span class="comment">//undefined,原因，u并不是一个函数对象，它只是一个对象，var u = ....</span></span><br></pre></td></tr></table></figure></li></ul><p>​                       </p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/1801532867953_.pic.jpg" alt="">                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          </p><p>  <img src="http://7xkluu.com1.z0.glb.clouddn.com/1811532867980_.pic.jpg" alt=""></p><p>我们给User.prototype设置了一个toString()函数，u是可以访问到的。</p><p>同样的，<code>u.__proto__</code>代表指向它构造函数的prototype，其实也是等于User.prototype.</p><p>那什么是原型链？如果一个原型对象的原型不为null，就是原型链，我们可以通过<code>__proto__</code>来遍历原型链（ES6）</p><p><strong>那ES5的继承和ES6的继承有什么区别？</strong></p><p>ES5的继承是通过prototype或构造函数机制来实现。<strong>ES5的继承实质上是先创建子类的实例对象，然后再将父类的方法添加到this上</strong>（Parent.apply(this)）。</p><p>ES6的继承机制完全不同，<strong>实质上是先创建父类的实例对象this（所以必须先调用父类的super()方法），然后再用子类的构造函数修改this</strong>。</p><blockquote><p>具体的：ES6通过class关键字定义类，里面有构造方法，类之间通过extends关键字实现继承。子类必须在constructor方法中调用super方法，否则新建实例报错。因为子类没有自己的this对象，而是继承了父类的this对象，然后对其进行加工。如果不调用super方法，子类得不到this对象。</p><p>ps：super关键字指代父类的实例，即父类的this对象。在子类构造函数中，调用super后，才可使用this关键字，否则报错。</p></blockquote><h3 id="如何判断一个变量是对象还是数组？"><a href="#如何判断一个变量是对象还是数组？" class="headerlink" title="如何判断一个变量是对象还是数组？"></a>如何判断一个变量是对象还是数组？</h3><p>第一念头是使用<strong>typeof</strong>，但是是有问题的，因为数组也是对象的一种，这个问题的问法其实应该是，<strong>如何判断一个对象是数组</strong>。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">var b = [1,2,3];</span><br><span class="line">typeof b;//&quot;object&quot;</span><br></pre></td></tr></table></figure><ul><li><p><strong>instanceof操作符</strong></p><p>这个操作符是检测对象的原型链是否指向构造函数的prototype对象的。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">var arr = [1,2,3,1];   </span><br><span class="line">alert(arr instanceof Array); // true</span><br></pre></td></tr></table></figure></li><li><p><strong>对象的constructor属性</strong></p><p>每个对象都有constructor的属性，指向“创建这个对象的函数”</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">arr.constructor == Array //true</span><br></pre></td></tr></table></figure></li><li><p><strong>Object.prototype.toString</strong></p><blockquote><p>Object.prototype.toString的行为：首先，取得对象的一个内部属性[[Class]]，然后依据这个属性，返回一个类似于”[object Array]”的字符串作为结果(看过ECMA标准的应该都知道，[[]]用来表示语言内部用到的、外部不可直接访问的属性，称为“内部属性”)。利用这 个方法，再配合call，我们可以取得任何对象的内部属性[[Class]]，然后把类型检测转化为字符串比较，以达到我们的目的。</p></blockquote><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">function isArrayFn (o) &#123;  </span><br><span class="line"> return Object.prototype.toString.call(o) === &apos;[object Array]&apos;;   </span><br><span class="line">&#125;</span><br><span class="line">var arr = [1,2,3,1];   </span><br><span class="line"> </span><br><span class="line">alert(isArrayFn(arr));// true</span><br></pre></td></tr></table></figure><p>call改变toString的this引用为待检测的对象，返回此对象的字符串表示，然后对比此字符串是否是’[object Array]’，以判断其是否是Array的实例.</p></li><li><p><strong>Array.isArray()</strong></p><p>ECMAScript5将<strong>Array.isArray()</strong>正式引入JavaScript，目的就是准确地检测一个值是否为数组。</p><p>IE9+、 Firefox 4+、Safari 5+、Opera 10.5+和Chrome都实现了这个方法。</p><p>但是在IE8之前的版本是不支持的。</p></li><li><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">var arr = [1,2,3,1];  </span><br><span class="line">var arr2 = [&#123; abac : 1, abc : 2 &#125;];  </span><br><span class="line"> </span><br><span class="line">function isArrayFn(value)&#123;</span><br><span class="line">if (typeof Array.isArray === &quot;function&quot;) &#123;</span><br><span class="line">return Array.isArray(value);    </span><br><span class="line">&#125;else&#123;</span><br><span class="line">return Object.prototype.toString.call(value) === &quot;[object Array]&quot;;    </span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br><span class="line">alert(isArrayFn(arr));// true</span><br></pre></td></tr></table></figure><p>typeof Array.isArray === “function” 来判断浏览器支不支持用isArray，不支持的话用Object.prototype.toString。因为Object.prototype.toString对识别内置对象时往往十分有用，但对于自定义对象就可能识别不出。</p></li></ul><h3 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h3><p>Promise是ES6为了解决异步编程所诞生的，主要用于ajax请求，回调函数，复杂操作判断。</p><p>PS：异步操作解决方案：<code>Promise</code>、<code>Generator</code>、定时器、还有ES7的<code>async</code></p><h3 id="document-visibilityState-amp-amp-document-hidden"><a href="#document-visibilityState-amp-amp-document-hidden" class="headerlink" title="document.visibilityState &amp;&amp; document.hidden"></a>document.visibilityState &amp;&amp; document.hidden</h3><p>PageVisibility API是用来判断页面可见性，即浏览器标签页被隐藏或者显示的判断。</p><p>document.visibilityState：</p><ul><li>visible：页面内容至少部分可见，即可能是已更非最小化窗口的可见标签页</li><li>hidden：页面内容对用户不可见，即可能是后台标签页或者最小化窗口等</li><li>prerender：网页内容被预渲染且用户不可见</li><li>unloaded：网页被卸载</li></ul><p>一般我们使用document.hidden就可以满足需求</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">function getHiddenProp()&#123;</span><br><span class="line">    var prefixes = [&apos;webkit&apos;,&apos;moz&apos;,&apos;ms&apos;,&apos;o&apos;];</span><br><span class="line">    </span><br><span class="line">    // if &apos;hidden&apos; is natively supported just return it</span><br><span class="line">    if (&apos;hidden&apos; in document) return &apos;hidden&apos;;</span><br><span class="line">    </span><br><span class="line">    // otherwise loop over all the known prefixes until we find one</span><br><span class="line">    for (var i = 0; i &lt; prefixes.length; i++)&#123;</span><br><span class="line">        if ((prefixes[i] + &apos;Hidden&apos;) in document) </span><br><span class="line">            return prefixes[i] + &apos;Hidden&apos;;</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    // otherwise it&apos;s not supported</span><br><span class="line">    return null;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">function isHidden() &#123;</span><br><span class="line">    var prop = getHiddenProp();</span><br><span class="line">    if (!prop) return false;</span><br><span class="line">    </span><br><span class="line">    return document[prop];</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><a href="http://www.css88.com/archives/6103" target="_blank" rel="noopener">http://www.css88.com/archives/6103</a></p><p>此属性需要注意兼容性。</p><ul><li><p>做一个保存草稿的页面，每隔十分钟会自动保存一次，如果在多个页面中打开了同一页面，怎样确保往数据库里存的是用户想要保存的内容。</p><p>sessionStorage + 修改时间戳，做异步写入，然后用事件节流的方式</p></li></ul><h3 id="querySelector和querySelectorAll"><a href="#querySelector和querySelectorAll" class="headerlink" title="querySelector和querySelectorAll"></a>querySelector和querySelectorAll</h3><p>这个为H5新特性。</p><ul><li>querySelector:返回指定元素节点的子树中匹配选择器的集合中的第一个元素，如果没有返回null</li><li>querySelectorAll:按文档顺序返回指定元素节点的子树中匹配选择器的元素集合，如果没有匹配返回空集合</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">&lt;div id=&quot;test&quot;&gt;</span><br><span class="line">        &lt;div class=&quot;dialog&quot;&gt;</span><br><span class="line">            &lt;p&gt;123&lt;/p&gt;</span><br><span class="line">            &lt;span&gt;456&lt;/span&gt;</span><br><span class="line">            &lt;div&gt;789&lt;/div&gt;</span><br><span class="line">            &lt;div class=&quot;text&quot;&gt;452&lt;/div&gt;</span><br><span class="line">        &lt;/div&gt;</span><br><span class="line">    &lt;/div&gt;</span><br><span class="line">    </span><br><span class="line"> var test=document.querySelector(&apos;#test&apos;);</span><br><span class="line">        var subDivs = test.querySelectorAll(&apos;div&apos;);</span><br><span class="line">        var text = document.querySelectorAll(&apos;div[class=text]&apos;);</span><br></pre></td></tr></table></figure><p>兼容性<br>IE8+（含）,针对mobile更优化</p><p><a href="http://www.cnblogs.com/dolphinX/p/3354318.html" target="_blank" rel="noopener">有bug</a></p><p><a href="http://blog.lxjwlt.com/front-end/2015/09/01/u-dont-know-queryselector.html?utm_source=caibaojian.com" target="_blank" rel="noopener">[译]你所不了解的querySelector</a></p><p>​                                          </p><h2 id="Web相关"><a href="#Web相关" class="headerlink" title="Web相关"></a>Web相关</h2><h3 id="XSS"><a href="#XSS" class="headerlink" title="XSS"></a>XSS</h3><p><a href="https://mp.weixin.qq.com/s/c_QTdLu6vsYcIiuPRZyjyA" target="_blank" rel="noopener">浅析前端安全之 XSS</a></p><p>看了上面那篇文章意识到一个很大的问题，因为我之前没有仔细想这方面的东西。但是我遇到过一次，表单中用户名以html形式渲染<code>&lt;h1&gt;123&lt;/h1&gt;</code>,他的名字设置为类似这样，结果json传回来后渲染到页面变成123 标题样式。</p><p>解决我方法是，我在输入表单这一块，先<code>encodeURIComponent</code>解析，发给后台，然后对收到json的这个数据使用<code>decodeURIComponent</code>进行解码。</p><p>vue中不使用v-html之类，直接  输出，使用转义功能。</p><p>要慢慢把以前的项目规范起来，防止漏洞才行，以后也要注意这一方面，有空再和后端探讨一下。</p><h3 id="跨域"><a href="#跨域" class="headerlink" title="跨域"></a>跨域</h3><p>首先说下我在实际项目中遇到的问题:</p><ul><li>一般都是Ajax请求的跨域问题，需要后端配合。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">$.ajax(&#123;</span><br><span class="line">    url: <span class="string">'xxx'</span>,</span><br><span class="line">    type: <span class="string">'get'</span>,</span><br><span class="line">    dataType: <span class="string">'jsonp'</span>,  <span class="comment">// 请求方式为jsonp</span></span><br><span class="line">    jsonpCallback: <span class="string">"onBack"</span>,    <span class="comment">// 自定义回调函数名</span></span><br><span class="line">    data: &#123;&#125;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><p>​    jsonp缺点：只能实现get一种请求。</p><p>遇到的一个错误<code>Uncaught SyntaxError: Unexpected token :</code></p><p>这是因为后台直接给我返回json，而我用jsonp请求，简单说下后台返回的格式：</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// jsonStr：json格式的数据</span></span><br><span class="line"><span class="keyword">return</span>  <span class="string">"jsonpCallback("</span> + jsonStr+ <span class="string">");"</span> ;</span><br></pre></td></tr></table></figure><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//jsonp</span></span><br><span class="line">jsonpCallback(&#123;</span><br><span class="line">    <span class="string">"url"</span>: <span class="string">"1234"</span>,</span><br><span class="line">    <span class="string">"name"</span>: <span class="string">"abcd"</span></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><ul><li>iframe跨域</li></ul><p>为什么会遇到这个问题，因为有次项目有个手机绑定uid的功能，需要用到第三方的手机验证登陆模块。</p><p>iframe地址为：a.yy.com/…</p><p>我的页面地址为：b.yy.com/…</p><p>这个时候会产生跨域问题，需要在两个页面里加代码：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">document</span>.domain = <span class="string">'yy.com'</span>;</span><br></pre></td></tr></table></figure><p>今天看到的这篇文章基本把所有跨域和解决方法列得很全面了：</p><p><a href="https://segmentfault.com/a/1190000011145364" target="_blank" rel="noopener">前端常见跨域解决方案（全）</a></p><h2 id="Vue"><a href="#Vue" class="headerlink" title="Vue"></a>Vue</h2><h3 id="MVVM"><a href="#MVVM" class="headerlink" title="MVVM"></a>MVVM</h3><p>最近被一篇文章刷屏了：<a href="https://mp.weixin.qq.com/s/7IW4WPTqjOieNVpQX9vBFQ" target="_blank" rel="noopener">别了，jQuery</a></p><p>文末那段话真实醍醐灌耳：</p><blockquote><p>“开发中使用库当然没问题，但前提是不要仅仅只知道怎么使用，更要知道它的工作原理。如果不能超越这些库，那在这些库变成你的拐杖之时，你也会随之“残废”。在使用某个库之前，一定要花时间学习掌握JavaScript和DOM。我们从一开头就强调“知其所以然”的重要性，告诉大家不能满足于仅仅“知其然”。如果使用了库，却不晓得其背后原理，无论对自己还是对产品都将是有害的。”</p><p>Ray建议，学习前端开发，本来应该是这个顺序：</p><ol><li>学习JavaScript</li><li>学习Web API</li><li>学习jQuery（或其他框架/库）</li></ol><p>但很多人实际上是从#3开始的，然后过了很久才开始#1和#2（甚至从来没想过#1和#2）。结果就是“只知其然，而不知其所以然”。</p></blockquote><p>说来惭愧，我就是那个从#3开始的人，所以现在确实业务代码写了很多，工作似乎都能完成，但是只有自己知道，面试的时候就知道，基础不行。不过没事，总有一天可以行的。</p><p>好了，回到正文：MVVM：</p><p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/8/87/MVVMPattern.png/330px-MVVMPattern.png" alt="MVVMPattern.png"></p><p><strong>Model–view–viewmodel</strong> (<strong>MVVM</strong>) is a software <a href="https://en.wikipedia.org/wiki/Architectural_pattern" target="_blank" rel="noopener">architectural pattern</a>.</p><p>MVVM最早由微软提出来，它借鉴了桌面应用程序的MVC思想，在前端页面中，把Model用纯JavaScript对象表示，View负责显示，两者做到了最大限度的分离。</p><p>把Model和View关联起来的就是ViewModel。ViewModel负责把Model的数据同步到View显示出来，还负责把View的修改同步回Model。</p><ul><li><p>常用的MVVM框架有：Angular，Backbone.js和我现在经常用的Vue.js</p></li><li><p>单向/双向绑定：</p><p>Vue为例，直白一点理解就是，单向绑定意思如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">p</span>&gt;</span>&#123;&#123;data&#125;&#125;<span class="tag">&lt;/<span class="name">p</span>&gt;</span> //负责显示的是DOM节点可以用&#123;&#123; &#125;&#125;来引用Model的属性</span><br></pre></td></tr></table></figure><p>双向绑定意思如下：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">p&gt;<span class="tag">&lt;<span class="name">input</span> <span class="attr">v-model</span>=<span class="string">"email"</span>&gt;</span><span class="tag">&lt;/<span class="name">p</span>&gt;</span> // 使用v-model指令，把这里的input和Model里的某个属性做双向绑定</span><br></pre></td></tr></table></figure></li><li><p>同步</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">&lt;ol&gt;</span><br><span class="line">    &lt;li v-<span class="keyword">for</span>=<span class="string">"t in todos"</span>&gt;</span><br><span class="line">        &lt;dl&gt;</span><br><span class="line">            &lt;dt&gt;&#123;&#123; t.name &#125;&#125;&lt;<span class="regexp">/dt&gt;</span></span><br><span class="line"><span class="regexp">            &lt;dd&gt;&#123;&#123; t.description &#125;&#125;&lt;/</span>dd&gt;</span><br><span class="line">        &lt;<span class="regexp">/dl&gt;</span></span><br><span class="line"><span class="regexp">    &lt;/</span>li&gt;</span><br><span class="line">&lt;<span class="regexp">/ol&gt;</span></span><br></pre></td></tr></table></figure><p>根据Modal里的todos变化，比如数组增加或减少，这里html会相应的进行DOM节点的增加或减少，完全由数据决定，开发者无需去关注html的DOM节点。</p><blockquote><p>Vue之所以能够监听Model状态的变化，是因为JavaScript语言本身提供了<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" target="_blank" rel="noopener">Proxy</a>或者<a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe" target="_blank" rel="noopener">Object.observe()</a>机制来监听对象状态的变化。但是，对于数组元素的赋值，却没有办法直接监听</p></blockquote></li><li><p>MVVM的适用范围</p><p>MVVM最大的优势是编写前端逻辑非常复杂的页面，尤其是需要大量DOM操作的逻辑，利用MVVM可以极大地简化前端页面的逻辑。</p><p>然而对于以展示逻辑为主的页面，例如，新闻，博客、文档等，是不建议使用MVVM展示数据，因为这些页面需要被搜索引擎索引，<strong>而搜索引擎无法获取使用MVVM并通过API加载的数据</strong>。</p><p>所以，需要SEO（Search Engine Optimization）的页面，不能使用MVVM展示数据。不需要SEO的页面，如果前端逻辑复杂，就适合使用MVVM展示数据，例如，工具类页面，复杂的表单页面，用户登录后才能操作的页面等等。</p></li></ul><h3 id="你或许不知道Vue的这些小技巧"><a href="#你或许不知道Vue的这些小技巧" class="headerlink" title="你或许不知道Vue的这些小技巧"></a>你或许不知道Vue的这些小技巧</h3><p>文章地址：<a href="http://obkoro1.com/2018/06/03/%E4%BD%A0%E6%88%96%E8%AE%B8%E4%B8%8D%E7%9F%A5%E9%81%93Vue%E7%9A%84%E8%BF%99%E4%BA%9B%E5%B0%8F%E6%8A%80%E5%B7%A7/" target="_blank" rel="noopener">你或许不知道Vue的这些小技巧</a>     <a href="https://juejin.im/post/5a587b46f265da3e3b7a7677" target="_blank" rel="noopener">Vue 实践过程中的几个问题</a></p><ul><li><p>Vue 数组/对象更新 视图不更新</p><p>这篇文章作者给了个例子，其实还蛮常见的。虽然我暂时没有遇到这个问题…因为我比较常用里面的第三种方法：替换数组/对象…</p><p>由于 JavaScript 的限制，Vue 不能检测以下变动的数组：</p><ol><li>当你利用索引直接设置一个项时，例如：<code>vm.items[indexOfItem] = newValue</code></li><li>当你修改数组的长度时，例如：<code>vm.items.length = newLength</code></li></ol><p>官网文档：<a href="https://cn.vuejs.org/v2/guide/list.html#%E6%95%B0%E7%BB%84%E6%9B%B4%E6%96%B0%E6%A3%80%E6%B5%8B" target="_blank" rel="noopener">数组更新检测</a></p><ul><li><p>Vue 包含一组观察数组的变异方法，会触发视图更新</p></li><li><p>替换数组</p></li><li><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">this</span>.$set(<span class="keyword">this</span>.arr, <span class="number">0</span>, <span class="string">"OBKoro1"</span>); <span class="comment">// 改变数组</span></span><br><span class="line"><span class="keyword">this</span>.$set(<span class="keyword">this</span>.obj, <span class="string">"c"</span>, <span class="string">"OBKoro1"</span>); <span class="comment">// 改变对象</span></span><br><span class="line"><span class="keyword">this</span>.arr.splice(newLength)</span><br></pre></td></tr></table></figure><blockquote><p>当你把一个普通的 JavaScript 对象传给 Vue 实例的 data 选项，Vue 将遍历此对象所有的属性，并使用<br>Object.defineProperty 把这些属性全部转为 getter/setter。</p><p>Object.defineProperty 是 ES5 中一个无法 shim 的特性，这也就是为什么 Vue 不支持 IE8 以及更低版本浏览器的原因。 </p><p>用户看不到 getter/setter，但是在内部它们让 Vue 追踪依赖，在属性被访问和修改时通知变化。这里需要注意的问题是浏览器控制台在打印数据对象时 getter/setter 的格式化并不同，所以你可能需要安装 vue-devtools 来获取更加友好的检查接口。</p><p> 每个组件实例都有相应的 watcher 实例对象，它会在组件渲染的过程中把属性记录为依赖，之后当依赖项的 setter 被调用时，会通知 watcher 重新计算，从而致使它关联的组件得以更新。 </p><p><a href="https://blog.csdn.net/zifeiyu130/article/details/78950244" target="_blank" rel="noopener">vue中数组和对象更改后视图不刷新的问题</a></p></blockquote><p>总结：数据的改变必须能够触发set方法，否则无法响应数据变化。</p></li></ul></li><li><p>一段取值的v-for</p><p><code>&lt;div v-for=&quot;n in 5&quot;&gt;&lt;span&gt;这里会被渲染5次，渲染模板&lt;/span&gt; &lt;/div&gt;</code></p><p>v-if尽量不要与v-for在同一节点使用(性能):</p><p>v-for 的优先级比 v-if 更高,如果它们处于同一节点的话，那么每一个循环都会运行一遍v-if。</p></li><li><p>Vue滚动行为</p><p>这个问题涉及到官网文档的以下两篇</p><p><a href="https://router.vuejs.org/zh/guide/essentials/history-mode.html" target="_blank" rel="noopener">HTML5 History 模式</a></p><p><a href="https://router.vuejs.org/zh/guide/advanced/scroll-behavior.html" target="_blank" rel="noopener">Vue Rouer 滚动行为</a></p><ul><li><p>history模式</p><p><a href="http://yoursite.com/#/a/b">http://yoursite.com/#/a/b</a>  //hash模式,即默认模式<br> <a href="http://yoursite.com/a/b">http://yoursite.com/a/b</a>  //history模式</p></li></ul></li><li><p>v-show和v-if</p></li></ul><ol><li>v-if是删除/添加Dom标签，不占据文档位置,v-show切换css的display属性，控制显示隐藏，还会占据文档Ω位置。</li><li><p>v-if会删除dom标签所以v-if性能消耗会高一些，需要频繁切换的话，使用v-show会好一点。</p><p>​</p></li></ol>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;JavaScript&quot;&gt;&lt;a href=&quot;#JavaScript&quot; class=&quot;headerlink&quot; title=&quot;JavaScript&quot;&gt;&lt;/a&gt;JavaScript&lt;/h2&gt;&lt;h3 id=&quot;原型&quot;&gt;&lt;a href=&quot;#原型&quot; class=&quot;headerli
      
    
    </summary>
    
    
      <category term="前端零碎" scheme="http://yoursite.com/tags/%E5%89%8D%E7%AB%AF%E9%9B%B6%E7%A2%8E/"/>
    
  </entry>
  
  <entry>
    <title>Animations(web动画归纳篇)</title>
    <link href="http://yoursite.com/2018/08/09/Animations/"/>
    <id>http://yoursite.com/2018/08/09/Animations/</id>
    <published>2018-08-09T12:46:28.000Z</published>
    <updated>2018-08-13T11:22:10.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="web动画形式"><a href="#web动画形式" class="headerlink" title="web动画形式"></a>web动画形式</h2><p><strong>经常使用的场景：</strong></p><ul><li><p>css3动画</p><figure class="highlight css"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="selector-class">.box</span> &#123;</span><br><span class="line">  <span class="attribute">-webkit-transform</span>: <span class="built_in">translate</span>(0, 0);</span><br><span class="line">  <span class="attribute">-webkit-transition</span>: -webkit-transform <span class="number">500ms</span>;</span><br><span class="line"></span><br><span class="line">  <span class="attribute">transform</span>: <span class="built_in">translate</span>(0, 0);</span><br><span class="line">  <span class="attribute">transition</span>: transform <span class="number">500ms</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="selector-class">.box</span><span class="selector-class">.move</span> &#123;</span><br><span class="line">  <span class="attribute">-webkit-transform</span>: <span class="built_in">translate</span>(100px, 100px);</span><br><span class="line">  <span class="attribute">transform</span>: <span class="built_in">translate</span>(100px, 100px);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>js控制样式:使用 JavaScript 来管理状态，只需在目标元素上设置相应的类，让浏览器去处理动画</p><p><code>box.classList.add(&#39;move&#39;)；</code></p></li><li><p>这种方法可以侦听元素的 <code>transitionend</code> 事件,兼容IE10</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> box = <span class="built_in">document</span>.querySelector(<span class="string">'.box'</span>);</span><br><span class="line">box.addEventListener(<span class="string">'transitionend'</span>, onTransitionEnd, <span class="literal">false</span>);</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">onTransitionEnd</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="comment">// Handle the transition finishing.</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="1-CSS3动画"><a href="#1-CSS3动画" class="headerlink" title="1. CSS3动画"></a>1. CSS3动画</h3><p>略</p><h3 id="2-使用-JavaScript-编写动画"><a href="#2-使用-JavaScript-编写动画" class="headerlink" title="2. 使用 JavaScript 编写动画"></a>2. 使用 JavaScript 编写动画</h3><p>为什么要使用javaScript动画，因为js动画可以完全控制元素在每个步骤的样式。这意味着您可以在您认为合适时减慢动画、暂停动画、停止动画、倒退动画和操纵元素。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> target = <span class="built_in">document</span>.querySelector(<span class="string">'.box'</span>);</span><br><span class="line"><span class="keyword">var</span> player = target.animate([</span><br><span class="line">  &#123;<span class="attr">transform</span>: <span class="string">'translate(0)'</span>&#125;,</span><br><span class="line">  &#123;<span class="attr">transform</span>: <span class="string">'translate(100px, 100px)'</span>&#125;</span><br><span class="line">], <span class="number">500</span>);</span><br><span class="line">player.addEventListener(<span class="string">'finish'</span>, <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  target.style.transform = <span class="string">'translate(100px, 100px)'</span>;</span><br><span class="line">&#125;);</span><br></pre></td></tr></table></figure><h3 id="3-HTML5新增的定时器requestAnimationFrame"><a href="#3-HTML5新增的定时器requestAnimationFrame" class="headerlink" title="3. HTML5新增的定时器requestAnimationFrame"></a>3. HTML5新增的定时器requestAnimationFrame</h3><p>setTimeout和setInterval的问题是，它们都不精确。它们的内在<a href="http://www.cnblogs.com/xiaohuochai/p/5773183.html#anchor3" target="_blank" rel="noopener">运行机制</a>决定了时间间隔参数实际上只是指定了把动画代码添加到浏览器UI线程队列中以等待执行的时间。如果队列前面已经加入了其他任务，那动画代码就要等前面的任务完成后再执行。</p><p>requestAnimationFrame采用系统时间间隔，保持最佳绘制效率，不会因为间隔时间过短，造成过度绘制，增加开销；也不会因为间隔时间太长，使用动画卡顿不流畅，让各种网页动画效果能够有一个统一的刷新机制，从而节省系统资源，提高系统性能，改善视觉效果.</p><p>总而言之，requestAnimationFrame相当于是把动画交给浏览器去执行，浏览器会基于当前页面情况来自行决定最佳的帧速率，从而更合理地使用CPU。</p><p>它兼容Android4.4及以上，IE10及以上，兼容性其实跟css3动画差不多，所以可能要根据需求配合setTimeout做降级处理。</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">if</span>(!<span class="built_in">window</span>.requestAnimationFrame)&#123;</span><br><span class="line">    <span class="keyword">var</span> lastTime = <span class="number">0</span>;</span><br><span class="line">    <span class="built_in">window</span>.requestAnimationFrame = <span class="function"><span class="keyword">function</span>(<span class="params">callback</span>)</span>&#123;</span><br><span class="line">        <span class="keyword">var</span> currTime = <span class="keyword">new</span> <span class="built_in">Date</span>().getTime();</span><br><span class="line">        <span class="keyword">var</span> timeToCall = <span class="built_in">Math</span>.max(<span class="number">0</span>,<span class="number">16.7</span>-(currTime - lastTime));</span><br><span class="line">        <span class="keyword">var</span> id  = <span class="built_in">window</span>.setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">            callback(currTime + timeToCall);</span><br><span class="line">        &#125;,timeToCall);</span><br><span class="line">        lastTime = currTime + timeToCall;</span><br><span class="line">        <span class="keyword">return</span> id;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (!<span class="built_in">window</span>.cancelAnimationFrame) &#123;</span><br><span class="line">    <span class="built_in">window</span>.cancelAnimationFrame = <span class="function"><span class="keyword">function</span>(<span class="params">id</span>) </span>&#123;</span><br><span class="line">        clearTimeout(id);</span><br><span class="line">    &#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>所以综上，我们可以在使用setTimeout的地方做动画时也使用这个新的定时器做优化。</p><h3 id="4-Web-Animations-API"><a href="#4-Web-Animations-API" class="headerlink" title="4. Web Animations API"></a>4. Web Animations API</h3><p>WAAPI是JavaScript 原生提供的的动画操作 API。</p><p>文章：</p><p><a href="https://www.zcfy.cc/article/css-animations-vs-web-animations-api-css-tricks-3306.html" target="_blank" rel="noopener">CSS Animations vs Web Animations API</a></p><ul><li><p>兼容性：Dan Wilson(<a href="https://codepen.io/danwilson" target="_blank" rel="noopener">@danvilson</a>) 写的<a href="https://codepen.io/danwilson/pen/xGBKVq/" target="_blank" rel="noopener">WAAPI 浏览器兼容测试</a>页面，目前只有极少部分的浏览器支持，但是 WAAPI 有完善的 <a href="https://github.com/web-animations/web-animations-js/tree/master" target="_blank" rel="noopener">Polyfill</a> 方案。</p></li><li><p>WAAPI的基础方法和jQuery的.animate()方法类似</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> element = <span class="built_in">document</span>.querySelector(<span class="string">'.animate-me'</span>);</span><br><span class="line">element.animate(keyframes, <span class="number">1000</span>);</span><br></pre></td></tr></table></figure><p><code>animate</code> 方法接受两个参数：关键帧和持续时间。与jQuery不同的是，它不仅具有浏览器原生支持等优点，而且还具有更高的性能。</p><p>第一个参数关键帧必须是一个数组对象。每一个对象是一个动画关键帧。下面是一个简单的示例：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> keyframes = [</span><br><span class="line">  &#123; <span class="attr">opacity</span>: <span class="number">0</span> &#125;,</span><br><span class="line">  &#123; <span class="attr">opacity</span>: <span class="number">1</span> &#125;</span><br><span class="line">];</span><br></pre></td></tr></table></figure><p>​</p></li></ul><h2 id="动画与性能"><a href="#动画与性能" class="headerlink" title="动画与性能"></a>动画与性能</h2><p><a href="https://www.html5rocks.com/zh/tutorials/speed/high-performance-animations/" target="_blank" rel="noopener">High Performance Animations</a></p><ul><li><p>注意动画不能导致性能问题</p><p>eg：</p><blockquote><p>给元素的 <code>width</code> 和 <code>height</code> 设置动画会改变其几何形状，并且可能导致页面上的其他元素移动或改变大小。此过程称为<em>布局</em>（在 Firefox 等基于 Gecko 的浏览器中称为<em>自动重排</em>），如果页面有很多元素，则可能开销很大。每当触发布局时，页面或其一部分通常需要进行绘制，这一般比布局操作本身更消耗资源。</p><p>应尽可能避免给触发布局或绘制的属性设置动画。对于大部分现代浏览器，这意味着将动画限制为 <code>opacity</code> 或 <code>transform</code>，两种都可经浏览器高度优化；动画是由 JavaScript 还是由 CSS 处理并不重要。</p></blockquote><p>​</p><p><img src="https://www.html5rocks.com/zh/tutorials/speed/high-performance-animations/cheap-operations.jpg" alt=""></p><blockquote><p>Chrome, Firefox, Safari 和 Opera 都对 transforms 和 opacity进行硬件加速。不幸的是，对于Internet Explorer 10+ 开启硬件加速的条件不是很明确，但值得庆幸的是当F12工具加入到IE11中的时候，这一点将变得清晰。</p><p>在Blink和WebKit内核的浏览器中，对于在CSS的transition或者animation中有opacity的改变的元素，将会为其创建一个图层。但也有很多开发者使用<code>translateZ(0)</code>或者<code>translate3d(0,0,0)</code>来人为地强制性地创建一个图层(硬件加速)。然而，需要有节制地增加图层；如果过分的增加图层，那么将会导致<a href="http://wesleyhales.com/blog/2013/10/26/Jank-Busting-Apples-Home-Page/" target="_blank" rel="noopener">闪烁</a>。</p><p>一个元素的变换，归结为改变它的位置，旋转角度和缩放。通常，位置的改变是使用<code>left</code>和<code>top</code>属性来改变的。问题是，如前面所述，<code>left</code>和<code>top</code>都会引起图层的变化，并且它的代价是昂贵的。更好的解决方案是使用不会引起图层变化的<code>translate</code>属性。</p></blockquote></li></ul><h3 id="CSS-对比-JavaScript-的性能"><a href="#CSS-对比-JavaScript-的性能" class="headerlink" title="CSS 对比 JavaScript 的性能"></a>CSS 对比 JavaScript 的性能</h3><p><strong>命令式动画(JavaScript)vs说明式动画(css)</strong></p><ul><li><p>JavaScript动画：</p><p>它在浏览器主进程的JavaScript中运行。主进程已经忙于运行其他的JavaScript，样式的计算，布局还有绘制。所以进程内存在这资源竞争。这实质上增加了掉帧的风险，可能这一帧是你认为最重要的帧。</p></li><li><p>CSS动画</p><p>作为替代的方案，你可以用CSS来实现你的渐变和动画。最主要的好处就是，浏览器会对动画进行优化。如果有需要，它会创建图层。并且可以在主进程之外完成一些操作。这意味着，如果浏览器正在主线程上运行一些高开销任务，则这些动画可以继续运行而不中断。它最主要的缺点就是CSS动画相对于Javascript动画而言，缺乏表现力。并且很难有意义地组织动画，这意味着创造动画会带来较高的复杂度和错误率。</p></li><li><p>如果任何动画触发绘制、布局或同时触发这两者，则“主线程”将必须执行工作。这点同时适用于基于 CSS 和 JavaScript 的动画，并且布局或绘制的开销可能拖慢与 CSS 或 JavaScript 执行相关的任何工作，使问题变得无意义。</p></li></ul><p><strong>总结：</strong></p><p><strong>JavaScript动画对比CSS动画：</strong></p><p>缺点：</p><ol><li>JavaScript在浏览器的主线程中运行,而主线程中还有其它需要运行的JavaScript脚本、样式计算、布局、绘制任务等,对其干扰导致线程可能出现阻塞,从而造成丢帧的情况。</li><li>代码的复杂度高于CSS动画</li></ol><p>优点：</p><ol><li>js动画控制能力强，可以完全控制元素在每个步骤的样式，如减慢动画、暂停动画、停止动画、倒退动画和操纵元素。</li><li>动画效果比css3动画丰富,有些动画效果,比如曲线运动,冲击闪烁,视差滚动效果,只有JavaScript动画才能完成</li><li>JS大多时候没有兼容性问题</li></ol><p><strong>CSS动画对比JavaScript动画</strong></p><p>缺点：</p><ol><li>CSS动画只能暂停,不能在动画中寻找一个特定的时间点,不能在半路反转动画,不能变换时间尺度,不能在特定的位置添加回调函数或是绑定回放事件,无进度报告</li><li>实现复杂动画代码冗长</li></ol><p>优点：</p><ol><li><p>浏览器可以对动画进行优化。</p><p>浏览器使用与 requestAnimationFrame 类似的机制,requestAnimationFrame比起setTimeout,setInterval设置动画的优势主要是:</p><p>1) requestAnimationFrame 会把每一帧中的所有DOM操作集中起来,在一次重绘或回流中就完成,并且重绘或回流的时间间隔紧紧跟随浏览器的刷新频率,一般来说,这个频率为每秒60帧。</p><p>2) 在隐藏或不可见的元素中requestAnimationFrame不会进行重绘或回流,这当然就意味着更少的的cpu,gpu和内存使用量。</p></li><li><p>强制使用硬件加速 (通过 GPU 来提高动画性能)</p><p>渲染线程分为main thread(主线程)和compositor thread(合成器线程)。如果CSS动画只是改变transform和opacity,这时整个CSS动画得以在compositor thread完成(而JS动画则会在main thread执行,然后触发compositor进行下一步操作)在JS执行一些昂贵的任务时,main thread繁忙,CSS动画由于使用了compositor thread可以保持流畅,</p></li><li><p>代码相对简单,性能调优方向固定</p></li></ol><p><em>在CSS动画或JS动画触发了paint或layout时,需要main thread进行Layer树的重计算,这时CSS动画或JS动画都会阻塞后续操作，所以只有用上了3D硬件加速或修改opacity时,css3动画的优势才会体现出来。</em></p><p>了解一个属性（由于支持度不高，暂不运用到项目）：<a href="https://developer.mozilla.org/zh-CN/docs/Web/CSS/will-change" target="_blank" rel="noopener">will-change</a>：为web开发者提供了一种告知浏览器该元素会有哪些变化的方法，这样浏览器可以在元素属性真正发生变化之前提前做好对应的优化准备工作。 这种优化可以将一部分复杂的计算工作提前准备好，使页面的反应更为快速灵敏。</p><p><a href="https://caniuse.com/#search=will-change" target="_blank" rel="noopener">兼容性</a>:IE不支持（含IE11），Android 4.4.4（含）以下不支持，ios9.2（含）以下不支持</p><p>其他参考文章：</p><p>  <a href="https://developers.google.com/web/fundamentals/design-and-ux/animations/css-vs-javascript?hl=zh-cn" target="_blank" rel="noopener">CSS 对比 JavaScript 动画</a></p><p><a href="https://www.cnblogs.com/xiaohuochai/p/5777186.html" target="_blank" rel="noopener">深入理解定时器系列第二篇——被誉为神器的requestAnimationFrame</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;web动画形式&quot;&gt;&lt;a href=&quot;#web动画形式&quot; class=&quot;headerlink&quot; title=&quot;web动画形式&quot;&gt;&lt;/a&gt;web动画形式&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;经常使用的场景：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;css3动画&lt;/
      
    
    </summary>
    
    
      <category term="web" scheme="http://yoursite.com/tags/web/"/>
    
  </entry>
  
  <entry>
    <title>iView之后台运营系统</title>
    <link href="http://yoursite.com/2018/04/05/%E4%BD%BF%E7%94%A8iview-ui%E6%9E%84%E5%BB%BA%E5%90%8E%E5%8F%B0%E8%BF%90%E8%90%A5%E7%B3%BB%E7%BB%9F/"/>
    <id>http://yoursite.com/2018/04/05/使用iview-ui构建后台运营系统/</id>
    <published>2018-04-05T11:46:28.000Z</published>
    <updated>2018-10-25T08:51:56.000Z</updated>
    
    <content type="html"><![CDATA[<p>前言：后台运营管理系统几乎是我这一年来一直在跟进的需求，因为随着产品线扩大，它本来由一个替补或者说增进的使用场景变成一个必不可缺的一部分。</p><p>PS,去年回广州重新找工作，告别了待了两年的深圳。还记得当时来到现在这家公司时我没用过工作流，没在实际项目中使用自动化构建，没有在实际项目中使用除Jquery外的开发框架，也因为之前的项目单一即便公司背景不错但换工作的时候还是碰壁。入职前两个月项目组刚建不久，每天和一群后台/客户端小哥哥一起奋战，赶着发版，开始人生中第一次996，累但是很满足。新项目组只有我一个前端，对业务不熟悉时经常跑大部门另一个前端组取经，感谢他们对我的帮助，几乎一周上手。哈哈觉得我的适应能力和学习能力还是棒棒的，这也验证了一句话，实践是检验真理唯一标准，学习一样东西最好的方法是去使用它，恩。</p><p>好了，不废话了。</p><h3 id="iView"><a href="#iView" class="headerlink" title="iView"></a>iView</h3><p>iView是一套基于Vue.JS的高质量UI组件库，官网地址：<a href="https://www.iviewui.com/docs/guide/install" target="_blank" rel="noopener">任意门</a></p><p>整个运营系统是以这套ui框架搭建，我觉得做完一个后台运营系统是基本符合开发需求，当然也不是说可以都照搬，一些特殊功能还是要结合产品需求做变更。</p><p>由于基于Vue，所以IE兼容不是很好。所以我在入口index.js中做了IE判断提醒，我觉得这是必须的。</p><p>项目基本结构：</p><p><img src="/2018/04/05/使用iview-ui构建后台运营系统/1.png" alt=""></p><ul><li><p>css:不必多说，就是用来写自定义样式的</p></li><li><p>data:用来存放iview框架，包括css和js</p></li><li><p>html：通用，引入通用链接如JQuery等，配置title等,html代码只有一句  <code>&lt;div id = &quot;app&quot;&gt;&lt;/div&gt;</code>，到时vue渲染使用</p></li><li><p>js：基本开发都是在这里</p><ul><li><p>api：用来存储各个tab的接口请求</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> dataType = <span class="string">'json'</span>;</span><br><span class="line"><span class="keyword">var</span> timeout = <span class="number">15000</span>;</span><br><span class="line"><span class="keyword">var</span> url = <span class="string">'接口通用域名地址'</span>;</span><br><span class="line"><span class="keyword">var</span> request = <span class="function"><span class="keyword">function</span>(<span class="params">opt</span>) </span>&#123;</span><br><span class="line"><span class="keyword">return</span> $.ajax(&#123;</span><br><span class="line">method: opt.method || <span class="string">'GET'</span>,</span><br><span class="line">dataType: dataType,</span><br><span class="line">timeout: timeout,</span><br><span class="line">url: url + opt.url,</span><br><span class="line">data: opt.data || <span class="literal">null</span></span><br><span class="line">&#125;);</span><br><span class="line">&#125;;</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line"><span class="comment">//数据1</span></span><br><span class="line">data1:<span class="function"><span class="keyword">function</span>(<span class="params">data</span>)</span>&#123;</span><br><span class="line">  <span class="keyword">return</span> request(&#123;</span><br><span class="line">url: <span class="string">'接口详细地址'</span>,</span><br><span class="line">data: data,</span><br><span class="line">&#125;);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>common</p><p><img src="/2018/04/05/使用iview-ui构建后台运营系统/2.png" alt=""></p><p>api.js：这里其实跟上面的api文件夹作用一样，区别在于它全部写在了一个文件里，一开始是直接用的这个，后来随着项目的扩大及接口改版，觉得还是要根据功能单独提取出来比较好，这样也有利于团队一起维护；</p><p>bus.js：这个不用多说，vue-router的中间组件</p><p>routeList.js：这个是用来存储单页应用跳转地址</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> page1 = <span class="built_in">require</span>(<span class="string">'module/page1/main'</span>);</span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">   routes: [</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/page1'</span>,</span><br><span class="line">      component: page</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'*'</span>,</span><br><span class="line">      redirect: <span class="string">'/home'</span></span><br><span class="line">    &#125;</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>tools.js:</p><p>这个是用来区分权限和放一些公用的组件</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> GetMenus =<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    ...</span><br><span class="line">&#125;<span class="comment">//tab权限区分</span></span><br><span class="line"><span class="built_in">module</span>.exports = &#123;</span><br><span class="line">  GetMenus: GetMenus,</span><br><span class="line">  ...</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>以上4个文件各司其职，可以看为通用组件。</p><p>然后接着看，lib文件夹是我用来放公共组件的，比如一些处理ajax的公共方法，vendor用来放第三方组件，比如vue-qrcode,用来显示二维码，这里是在支付这一块需要用到，比如微信支付。</p><p>然后各个主要需求内容其实都是在module文件里。这里就是可以像平时写vue页面一样，在每个页面写好你的功能就可以。</p><p>整个框架基本就是这样，蛮明朗的。vue+iviewUi，前端+后台的对接，就可以完成这套运营系统了。各个页面的信息基本独立，公共的部分提取出来，一些需要传递的信息可以使用busEvents，无需引用vuex，其次ajax、功能模块单独区分，后期维护和其他人接手的话基本无成本，查找也方便。其他的使用在iview官网都可以找到解决办法，然后接下来介绍下其他特别的地方。</p></li></ul></li></ul><h3 id="其他"><a href="#其他" class="headerlink" title="其他"></a>其他</h3><p>在使用iView有没有遇到问题，当然有…有些是踩到的小坑，有些是iview满足不了你的需求，你要自己解决。</p><ul><li><p><code>&lt;Time-picker format=&quot;HH:mm&quot; type=&quot;timerange&quot; v-model=&quot;timeInterval&quot;  placeholder=&quot;推荐时间段&quot; style=&quot;width: 400px;&quot;&gt;&lt;/Time-picker&gt;</code></p><p>当timeInterval定义为字符串<code>timeInterval:&#39;&#39;</code>会把页面搞崩，因为动态监听的值类型问题，必须为数组。</p></li><li><p>二级联动</p><p>iView里有二级联动的组件<code>cascader</code>,但是是在一个选择框进行分级，我的需求是父子选择框是独立的选择框，所以仍然用到<code>select</code></p><p>所以这里要自己处理逻辑：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">computed: &#123;</span><br><span class="line">    self: <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>;</span><br><span class="line">    &#125;,</span><br><span class="line">   <span class="comment">//第二个选择框</span></span><br><span class="line">      levels:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">        <span class="keyword">var</span> levels =[],selectedDepart = <span class="keyword">this</span>.$data.category_id;   </span><br><span class="line">        <span class="keyword">this</span>.$data.categorys.forEach(<span class="function"><span class="keyword">function</span>(<span class="params">d</span>)</span>&#123;</span><br><span class="line">          <span class="keyword">if</span>(d.id == selectedDepart)&#123;</span><br><span class="line">            levels = d.levels; </span><br><span class="line">          &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        <span class="keyword">return</span> levels;</span><br><span class="line">      &#125;,</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">  <span class="comment">&lt;!--父选择框--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">Form-item</span> <span class="attr">label</span>=<span class="string">"选择品类"</span> <span class="attr">prop</span>=<span class="string">"coefficient"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">Select</span> <span class="attr">v-model</span>=<span class="string">"category_id"</span> <span class="attr">style</span>=<span class="string">"width:350px"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">Option</span> <span class="attr">v-for</span>=<span class="string">"item in categorys"</span> <span class="attr">:value</span>=<span class="string">"item.id"</span> <span class="attr">:key</span>=<span class="string">"item.id"</span>&gt;</span>&#123;&#123;item.category_name&#125;&#125;<span class="tag">&lt;/<span class="name">Option</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">Select</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">Form-item</span>&gt;</span> </span><br><span class="line"><span class="comment">&lt;!--子选择框--&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">Form-item</span> <span class="attr">label</span>=<span class="string">"段位"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">Select</span> <span class="attr">v-model</span>=<span class="string">"level1"</span> <span class="attr">style</span>=<span class="string">"width:350px"</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">Option</span> <span class="attr">v-for</span>=<span class="string">"item in levels"</span> <span class="attr">:value</span>=<span class="string">"item.level"</span> <span class="attr">:key</span>=<span class="string">"item"</span>&gt;</span>&#123;&#123;item.name&#125;&#125;<span class="tag">&lt;/<span class="name">Option</span>&gt;</span>  </span><br><span class="line"><span class="tag">&lt;/<span class="name">Select</span>&gt;</span></span><br><span class="line">   <span class="tag">&lt;/<span class="name">Form-item</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>待续…</p><p>​</p></li></ul><p>​    其实在项目中会遇到各种情况，比如你获取到的数据跟呈现在页面的数据可能是两种形式，中间的处理当然是需要自己写，框架拯救不了你。还有一些东西是可以利用框架来进行拓展，比如<code>Modal</code>弹框你可以用来做查看图片，具体情况具体分析。因为我没使用过elementUI，所以我也不知道具体的区别在哪里，简单看文档的话感觉是很相似的。无论是用iView还是其他，这些说到底都是一种辅助作用，简洁开发流程和优化呈现方式，作为前端<strong>应该就算它们提供不了功能也要能自己写出来</strong>，不能以框架没有做到为借口。打个很简单的比方，<code>Checkbox</code>可以用于多选，它也提供了一个全选的功能，那如果没有提供的话，我们也应该自己能写得出。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">i-form</span> <span class="attr">inline</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">Form-item</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">Checkbox</span> <span class="attr">style</span>=<span class="string">"margin-left: 10px;"</span> <span class="attr">v-model</span>=<span class="string">"selectAll"</span>  <span class="attr">v-if</span>=<span class="string">"ifselectAll"</span>&gt;</span>本页全选<span class="tag">&lt;/<span class="name">Checkbox</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">p</span> <span class="attr">style</span>=<span class="string">"margin-left: 10px;"</span> <span class="attr">v-else</span>&gt;</span>已选择&#123;&#123;muchcount&#125;&#125;位<span class="tag">&lt;/<span class="name">p</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;/<span class="name">Form-item</span>&gt;</span>    </span><br><span class="line"> <span class="tag">&lt;/<span class="name">i-form</span>&gt;</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">data: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">   <span class="keyword">return</span> &#123;</span><br><span class="line">     self: <span class="keyword">this</span>,</span><br><span class="line">     columns: [&#123;</span><br><span class="line">         title: <span class="string">'选择'</span>,</span><br><span class="line">         key: <span class="string">'choose'</span>,</span><br><span class="line">         width: <span class="number">50</span>,</span><br><span class="line">         render: <span class="function"><span class="keyword">function</span> (<span class="params">row, columns, index</span>) </span>&#123;</span><br><span class="line">           <span class="keyword">return</span> <span class="string">'&lt;Checkbox  disabled v-model="self.muchids.num'</span> + index + <span class="string">'"   @on-change="ifchange('</span> + row.id + <span class="string">')" v-if="self.selectAll"&gt;&lt;/Checkbox&gt;&lt;Checkbox  v-model="self.muchids.num'</span> + index + <span class="string">'"   @on-change="ifchange('</span> + row.id + <span class="string">')" v-else&gt;&lt;/Checkbox&gt;'</span></span><br><span class="line">         &#125;</span><br><span class="line">       &#125;,</span><br><span class="line">   ]&#125;,</span><br><span class="line">   ...</span><br><span class="line">   ...</span><br><span class="line">   methods:&#123;</span><br><span class="line">       <span class="comment">//多选选择判断</span></span><br><span class="line">   ifchange: <span class="function"><span class="keyword">function</span> (<span class="params">id</span>) </span>&#123;</span><br><span class="line">     <span class="keyword">var</span> self = <span class="keyword">this</span>;</span><br><span class="line">     <span class="keyword">var</span> index = self.muchList.indexOf(id)</span><br><span class="line">     <span class="built_in">console</span>.log(index)</span><br><span class="line">     <span class="keyword">if</span> (index != <span class="number">-1</span>) &#123;</span><br><span class="line">       self.muchList.splice(index, <span class="number">1</span>)</span><br><span class="line">     &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">       self.muchList.push(id);</span><br><span class="line"></span><br><span class="line">     &#125;</span><br><span class="line">     self.ifselectAll = self.muchList.length ? <span class="literal">false</span> : <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">     self.muchcount = self.muchList.length;</span><br><span class="line">     <span class="built_in">console</span>.log(self.muchList)</span><br><span class="line"></span><br><span class="line">   &#125;,</span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure><p>这样我就自己写出了一个全选的功能：</p><p><img src="/2018/04/05/使用iview-ui构建后台运营系统/3.png" alt=""></p><p><img src="/2018/04/05/使用iview-ui构建后台运营系统/4.png" alt=""></p><p>以上只是个栗子，建议可以直接用<code>checkbox</code>即可。框架和工具是为了辅助我们更好的开发，而不是去限制我们开发，这是我在这个过程中意识到的最大的收获。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;前言：后台运营管理系统几乎是我这一年来一直在跟进的需求，因为随着产品线扩大，它本来由一个替补或者说增进的使用场景变成一个必不可缺的一部分。&lt;/p&gt;
&lt;p&gt;PS,去年回广州重新找工作，告别了待了两年的深圳。还记得当时来到现在这家公司时我没用过工作流，没在实际项目中使用自动化构
      
    
    </summary>
    
    
      <category term="vue" scheme="http://yoursite.com/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>Vue组件间的通信</title>
    <link href="http://yoursite.com/2017/12/05/Vue%E7%BB%84%E4%BB%B6%E9%97%B4%E7%9A%84%E9%80%9A%E4%BF%A1/"/>
    <id>http://yoursite.com/2017/12/05/Vue组件间的通信/</id>
    <published>2017-12-05T13:46:28.000Z</published>
    <updated>2018-07-23T04:16:16.000Z</updated>
    
    <content type="html"><![CDATA[<ul><li>场景：<br>某个活动页需要在a页面填写表单，调取接口，接口返回结果如果成功则显示在b页面，如果失败则在a页面提示。</li><li>方案：使用vue单页面应用，分为entrance组件和room组件</li><li><p>思路：调取接口这一步需要在a组件完成，如果失败才能够直接在a(entrance组件)提示，如果成功需要把数据传给b(room组件)。</p><p>以上，进入正题，vue组件间的通信要怎么做，给出思路：</p><h3 id="一-子1传父，父传子2"><a href="#一-子1传父，父传子2" class="headerlink" title="一.子1传父，父传子2"></a>一.子1传父，父传子2</h3><p>这是最原始的做法。<br><img src="http://s3.51cto.com/wyfs02/M02/8A/7E/wKiom1gyapyjDebRAABntyrS_o8091.png" alt="img"><br>(网图)以上基本就可以概括。</p></li><li><p>父组件向子组件通信<br>这是很常用的一种情况。官网有写：<a href="https://cn.vuejs.org/v2/guide/components.html#%E9%80%9A%E8%BF%87-Prop-%E5%90%91%E5%AD%90%E7%BB%84%E4%BB%B6%E4%BC%A0%E9%80%92%E6%95%B0%E6%8D%AE" target="_blank" rel="noopener">链接</a></p><blockquote><p>通过Props向子组件传递数据…</p><p>Prop 是你可以在组件上注册的一些自定义特性。当一个值传递给一个 prop 特性的时候，它就变成了那个组件实例的一个属性。</p><p>​</p></blockquote><p>prop 是<strong>单向绑定</strong>的：当父组件的属性变化时，将传导给子组件，但是不会反过来。这是为了防止子组件无意修改了父组件的状态，所以<strong>不应该在子组件内部改变prop</strong>,每次父组件更新时，子组件的所有 prop 都会更新为最新值。</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">    父组件：</span><br><span class="line">    <span class="tag">&lt;<span class="name">input</span> <span class="attr">v-model</span>=<span class="string">"msg"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">hr</span>&gt;</span></span><br><span class="line">    子组件：</span><br><span class="line">    <span class="tag">&lt;<span class="name">child</span> <span class="attr">:message</span>=<span class="string">"msg"</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">        el:<span class="string">'#app'</span>,</span></span><br><span class="line"><span class="undefined">        data:&#123;</span></span><br><span class="line"><span class="javascript">            msg:<span class="string">'Hello World'</span></span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="undefined">        components:&#123;</span></span><br><span class="line"><span class="javascript">            <span class="string">'child'</span>:&#123;</span></span><br><span class="line"><span class="javascript">                props:[<span class="string">'message'</span>],</span></span><br><span class="line"><span class="xml">                template:'<span class="tag">&lt;<span class="name">input</span> <span class="attr">v-model</span>=<span class="string">"message"</span>&gt;</span>'</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;)</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>如果需要改变prop：</p><ul><li><p>prop作为初始值传入，子组件需要将它作为本地数值的初始值使用<br>定义一个局部data属性，并将prop的初始值作为局部数据的初始值</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">props:[data1],</span><br><span class="line">data:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"><span class="keyword">return</span> &#123;</span><br><span class="line">      counter:<span class="keyword">this</span>.data1</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li><li><p>prop作为需要被转变的原始值传入</p><p>定义一个computed属性</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">props:[data2],</span><br><span class="line">computed:&#123;</span><br><span class="line">computedSize:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">      <span class="keyword">return</span> <span class="keyword">this</span>.data2.trim().toLowerCase();</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li></ul><h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><p>子组件想要获取父组件的data</p><p>父组件：</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">child</span> <span class="attr">:msg</span>=<span class="string">"message"</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">import</span> child <span class="keyword">from</span> <span class="string">'./child.vue'</span>;</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="undefined">    components: &#123;</span></span><br><span class="line"><span class="undefined">        child</span></span><br><span class="line"><span class="undefined">    &#125;,</span></span><br><span class="line"><span class="undefined">    data () &#123;</span></span><br><span class="line"><span class="javascript">        <span class="keyword">return</span> &#123;</span></span><br><span class="line"><span class="javascript">            message: <span class="string">'123'</span>;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>子组件:child.vue</p><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">template</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span>&#123;&#123;msg&#125;&#125;<span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span></span><br><span class="line"><span class="undefined">    props: &#123;</span></span><br><span class="line"><span class="undefined">        msg: &#123;</span></span><br><span class="line"><span class="javascript">            type: <span class="built_in">String</span>,</span></span><br><span class="line"><span class="javascript">            required: <span class="literal">true</span></span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;</span></span><br><span class="line"><span class="undefined">&#125;</span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure></li><li><p>子组件向父组件通信</p><p><a href="https://cn.vuejs.org/v2/guide/components.html#%E9%80%9A%E8%BF%87%E4%BA%8B%E4%BB%B6%E5%90%91%E7%88%B6%E7%BA%A7%E7%BB%84%E4%BB%B6%E5%8F%91%E9%80%81%E6%B6%88%E6%81%AF" target="_blank" rel="noopener">官网链接</a></p><blockquote><p>通过事件向父级组件发送消息</p></blockquote><p>每个vue实例都实现了事件接口：</p><ol><li>使用<strong><em>$on</em></strong>监听事件</li><li>使用<strong><em>$emit</em></strong>触发事件，回调给父组件</li></ol><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">parent</span>&gt;</span><span class="tag">&lt;/<span class="name">parent</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"> </span><br><span class="line"><span class="comment">&lt;!--父组件--&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">template</span> <span class="attr">id</span>=<span class="string">"parent-template"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>父组件的数据是：<span class="tag">&lt;/<span class="name">span</span>&gt;</span>  ---&gt; `parentMsg`</span><br><span class="line">        <span class="tag">&lt;<span class="name">child</span> @<span class="attr">get-message</span>=<span class="string">"get"</span>&gt;</span><span class="tag">&lt;/<span class="name">child</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//注册父组件</span></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> Parent = Vue.component(<span class="string">'parent'</span>,&#123;</span></span><br><span class="line"><span class="javascript">        template: <span class="string">'#parent-template'</span>,</span></span><br><span class="line"><span class="undefined">        data()&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">return</span> &#123;<span class="attr">parentMsg</span>:<span class="string">'111'</span>&#125;</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="comment">//接收子组件传过来的数据</span></span></span><br><span class="line"><span class="undefined">        methods:&#123;</span></span><br><span class="line"><span class="javascript">            get:<span class="function"><span class="keyword">function</span>(<span class="params">msg</span>)</span>&#123;</span></span><br><span class="line"><span class="undefined">                alert(msg);</span></span><br><span class="line"><span class="javascript">                <span class="keyword">this</span>.parentMsg = msg;</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="xml"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span></span><br></pre></td></tr></table></figure><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--子组件--&gt;</span></span><br><span class="line"></span><br><span class="line"><span class="tag">&lt;<span class="name">template</span> <span class="attr">id</span>=<span class="string">"child-template"</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">div</span>&gt;</span></span><br><span class="line">        <span class="tag">&lt;<span class="name">span</span>&gt;</span>子组件的数据是：<span class="tag">&lt;/<span class="name">span</span>&gt;</span>  ---&gt; childMsg</span><br><span class="line">        <span class="tag">&lt;<span class="name">button</span> @<span class="attr">click</span>=<span class="string">"send"</span>&gt;</span>发送<span class="tag">&lt;/<span class="name">button</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">template</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span>&gt;</span><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="comment">//注册子组件</span></span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript">    <span class="keyword">var</span> Child = Vue.component(<span class="string">'child'</span>,&#123;</span></span><br><span class="line"><span class="javascript">        template:<span class="string">'#child-template'</span>,</span></span><br><span class="line"><span class="undefined">        data()&#123;</span></span><br><span class="line"><span class="javascript">            <span class="keyword">return</span> &#123;<span class="attr">childMsg</span>:<span class="string">'99999'</span>&#125;</span></span><br><span class="line"><span class="undefined">        &#125;,</span></span><br><span class="line"><span class="javascript">        <span class="comment">//把子组件数据发送给父组件</span></span></span><br><span class="line"><span class="undefined">        methods:&#123;</span></span><br><span class="line"><span class="javascript">           send:<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span></span><br><span class="line"><span class="javascript">               <span class="keyword">this</span>.$emit(<span class="string">'get-message'</span>, <span class="keyword">this</span>.childMsg)</span></span><br><span class="line"><span class="undefined">            &#125;</span></span><br><span class="line"><span class="undefined">        &#125;</span></span><br><span class="line"><span class="undefined">    &#125;);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="javascript"><span class="keyword">var</span> vm = <span class="keyword">new</span> Vue(&#123;</span></span><br><span class="line"><span class="javascript">      el:<span class="string">'#app'</span>,</span></span><br><span class="line"><span class="undefined">      components:&#123;</span></span><br><span class="line"><span class="javascript">          <span class="string">'parent'</span>: Parent</span></span><br><span class="line"><span class="undefined">      &#125;</span></span><br><span class="line"><span class="undefined">  &#125;);</span></span><br><span class="line"><span class="undefined"></span></span><br><span class="line"><span class="undefined"></span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure><p>​</p><h3 id="二-非父子组件、兄弟组件之间的数据传递"><a href="#二-非父子组件、兄弟组件之间的数据传递" class="headerlink" title="二.非父子组件、兄弟组件之间的数据传递"></a>二.非父子组件、兄弟组件之间的数据传递</h3><ul><li><strong>$on</strong>方法监听一个事件</li><li><strong>$emit</strong>方法触发一个事件</li><li>Vue官方推荐使用一个Vue实例作为中央事件总线 —— Bus</li><li>实例：<br>在组件中，可以使用<strong>$emit</strong>， <strong>$on</strong>，<strong>$off</strong> 分别来分发、监听、取消监听事件：<br>  直接到全局定义bus：</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> eventBus = &#123;</span><br><span class="line">    install(Vue,options) &#123;</span><br><span class="line">        Vue.prototype.$bus = vue</span><br><span class="line">    &#125;</span><br><span class="line">&#125;;</span><br><span class="line">Vue.use(eventBus);</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="comment">//分发事件的组件A</span></span><br><span class="line">methods: &#123;</span><br><span class="line">  todo: <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">    <span class="keyword">this</span>.$bus.$emit(<span class="string">'todoSth'</span>, params);  <span class="comment">//params是传递的参数</span></span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">// 监听事件的组件B</span></span><br><span class="line">created() &#123;</span><br><span class="line">  <span class="keyword">this</span>.$bus.$on(<span class="string">'todoSth'</span>, (params) =&gt; &#123;  <span class="comment">//获取传递的参数并进行操作</span></span><br><span class="line">      <span class="comment">//todo something</span></span><br><span class="line">  &#125;)</span><br><span class="line">&#125;,</span><br><span class="line"><span class="comment">// 最好在组件销毁前 清除事件监听</span></span><br><span class="line">beforeDestroy () &#123;</span><br><span class="line">  <span class="keyword">this</span>.$bus.$off(<span class="string">'todoSth'</span>);</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure></li></ul><p>​    或者将 <strong>事件中间件</strong>单独拎出来（需要注意在组件里引用）</p><p>​    bus.js:<br>  <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> bus = <span class="keyword">new</span> Vue();</span><br><span class="line"><span class="built_in">module</span>.exports = bus;</span><br></pre></td></tr></table></figure></p><p>​    分发事件的组件A：<br>  <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"> <span class="keyword">import</span> bus <span class="keyword">from</span> <span class="string">'../common/bus.js'</span></span><br><span class="line"> methods:&#123;</span><br><span class="line">sendData()&#123;</span><br><span class="line"><span class="keyword">this</span>.data = <span class="string">"123"</span></span><br><span class="line">&#125;</span><br><span class="line"> &#125;</span><br><span class="line"> beforeDestroy() &#123;</span><br><span class="line">     bus.$emit(<span class="string">'pbgdata'</span>, <span class="keyword">this</span>.data);<span class="comment">//'pbgdata'为组件的eventName，用于区分监听不同的组件内容</span></span><br><span class="line">   &#125;</span><br></pre></td></tr></table></figure></p><p>​    接收事件的组件B：<br>  <figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> bus <span class="keyword">from</span> <span class="string">'../common/bus.js'</span></span><br><span class="line"></span><br><span class="line">created() &#123;</span><br><span class="line">    bus.$on(<span class="string">'pbgdata'</span>, (data) =&gt; &#123;</span><br><span class="line">      <span class="built_in">console</span>.log(data)<span class="comment">//这就是从A组件得到的数据</span></span><br><span class="line"></span><br><span class="line">    &#125;)</span><br><span class="line">    </span><br><span class="line">    </span><br><span class="line">  &#125;,</span><br><span class="line"> beforeDestroy() &#123;</span><br><span class="line">    bus.$off(<span class="string">'pbgdata'</span>);</span><br><span class="line">  &#125;,</span><br></pre></td></tr></table></figure></p><p>从上面可以看出，我是在beforeDestroy()去分发事件，同时在B组件的created去监听事件，在beforeDes()去销毁，这是为啥？<br>这里就是遇到的另一个问题：</p><h3 id="vue-router中使用EventBus传值的坑"><a href="#vue-router中使用EventBus传值的坑" class="headerlink" title="vue-router中使用EventBus传值的坑"></a>vue-router中使用EventBus传值的坑</h3><p>一开始我在A组件得到数据后就使用$emit分发，然后第一次在B的created里并没有拿到（无销毁操作），第二次进入才拿到，且多次进入会打印多行结果。</p><blockquote><p>vue-router切换的时候，会先加载新的组件，当新的组件渲染好但是还没mount的时候，销毁旧组件，然后再挂载新组件，也就是说当B页面的生命周期进行到beforeMount的时候，下一步走到的就是A页面的beforeDestory方法和接下去的destroyed方法<br>所以我们再B组件的created方法里去使用<strong>$on</strong> 去监听自定义事件时<strong>$emit</strong>事件已经发出去了，这个时候监听器还没有注册，所以才需要再A的beforeDestroy或者destroyed去执行$emit。<br>以下为找的的vue-router切换时相关生命周期（网图）：<br><img src="https://www.tuchuang001.com/images/2018/04/27/5763769-1c04ab921c3d4876.png" alt="img"></p></blockquote><p>总结下就是这样的步骤：</p><p>新组件: beforeCreate<br>新组件: created<br>新组件: beforeMount<br>旧组件: beforeDestory<br>旧组件: destroy<br>新组件： mounted</p><h3 id="其他：当应用足够复杂情况下，请使用vuex进行数据管理。"><a href="#其他：当应用足够复杂情况下，请使用vuex进行数据管理。" class="headerlink" title="其他：当应用足够复杂情况下，请使用vuex进行数据管理。"></a>其他：当应用足够复杂情况下，请使用<a href="https://vuex.vuejs.org/zh/guide/" target="_blank" rel="noopener">vuex</a>进行数据管理。</h3><p>参考链接：</p><p><a href="https://www.limuyang.cc/2018/03/31/vue-router%E4%B8%AD%E4%BD%BF%E7%94%A8EventBus%E4%BC%A0%E5%80%BC%E9%9C%80%E8%A6%81%E6%B3%A8%E6%84%8F%E5%88%B0%E7%9A%84%E9%97%AE%E9%A2%98/" target="_blank" rel="noopener">vue-router中使用EventBus传值需要注意到的问题</a></p><p><a href="https://juejin.im/post/59ec95006fb9a0451c398b1a" target="_blank" rel="noopener">聊聊 Vue.js 组件间通信</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;ul&gt;
&lt;li&gt;场景：&lt;br&gt;某个活动页需要在a页面填写表单，调取接口，接口返回结果如果成功则显示在b页面，如果失败则在a页面提示。&lt;/li&gt;
&lt;li&gt;方案：使用vue单页面应用，分为entrance组件和room组件&lt;/li&gt;
&lt;li&gt;&lt;p&gt;思路：调取接口这一步需要在a组件完
      
    
    </summary>
    
    
      <category term="vue" scheme="http://yoursite.com/tags/vue/"/>
    
  </entry>
  
  <entry>
    <title>论一次找bug经历</title>
    <link href="http://yoursite.com/2017/07/29/%E8%AE%BA%E4%B8%80%E6%AC%A1%E6%89%BEbug%E7%BB%8F%E5%8E%86/"/>
    <id>http://yoursite.com/2017/07/29/论一次找bug经历/</id>
    <published>2017-07-29T05:35:24.000Z</published>
    <updated>2019-07-03T01:58:14.000Z</updated>
    
    <content type="html"><![CDATA[<h4 id="某日故障反馈群报某页面极个别用户无法获取数据，遂查。"><a href="#某日故障反馈群报某页面极个别用户无法获取数据，遂查。" class="headerlink" title="某日故障反馈群报某页面极个别用户无法获取数据，遂查。"></a>某日故障反馈群报某页面极个别用户无法获取数据，遂查。</h4><p>network返回<strong>Provisional headers are shown</strong></p><p><img src="/2017/07/29/论一次找bug经历/p1.jpg" alt="p1"></p><p>查看发现</p><p><img src="/2017/07/29/论一次找bug经历/@p2.jpg" alt="p2"></p><p>就是说根本没有拿到接口返回的数据，甚至根本可能没有发成功。</p><p>网上查都推荐看chrome://net-internals，那就来看下吧。</p><p>老实说一堆东西我看的也是半知不解，但是有几行觉得是关键：</p><p><img src="/2017/07/29/论一次找bug经历/p3.png" alt="p3"></p><p>可见发送头部是成功的，问题出在解析那里，read headers时间太长，直接导致cancelled，也就是说，是服务器相应太慢导致异常，那跟我前端应该没啥关系吧。</p><p>继续回到页面，15s后取消请求，为什么是15s，因为我的ajax的timeout超时设置了15s，把这个时间延长至5分钟，再看下原因。这次发现后端在2分钟后给我返回504，跟上面的解释对的上了。</p><p>后面就是告知后端同学查原因，后端反馈是这个用户名下列表数据量过大，导致查询过慢，直接超时，后面做了优化，已正常使用。</p><p>导致Provisional headers are shown其实原因可能多样，比如插件比如被某些扩展如 Adblock 给拦截比如被墙，还是要具体情况具体分析。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h4 id=&quot;某日故障反馈群报某页面极个别用户无法获取数据，遂查。&quot;&gt;&lt;a href=&quot;#某日故障反馈群报某页面极个别用户无法获取数据，遂查。&quot; class=&quot;headerlink&quot; title=&quot;某日故障反馈群报某页面极个别用户无法获取数据，遂查。&quot;&gt;&lt;/a&gt;某日故障反馈群报
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>提高网页性能的超实用方法</title>
    <link href="http://yoursite.com/2017/04/05/%E6%8F%90%E9%AB%98%E7%BD%91%E9%A1%B5%E6%80%A7%E8%83%BD%E7%9A%84%E8%B6%85%E5%AE%9E%E7%94%A8%E6%96%B9%E6%B3%95/"/>
    <id>http://yoursite.com/2017/04/05/提高网页性能的超实用方法/</id>
    <published>2017-04-05T11:06:01.000Z</published>
    <updated>2019-07-03T08:22:26.000Z</updated>
    
    <content type="html"><![CDATA[<!doctype html><html><head><meta name="generator" content="Hexo 3.8.0"><meta charset="UTF-8"><meta name="viewport" content="width=device-width initial-scale=1"><title>提高网页性能的超实用方法.md</title><link href="http://fonts.googleapis.com/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext" rel="stylesheet" type="text/css"><style type="text/css">html, body {overflow-x: initial !important;}.CodeMirror { height: auto; }.CodeMirror-scroll { overflow-y: hidden; overflow-x: auto; }.CodeMirror-lines { padding: 4px 0px; }.CodeMirror pre { }.CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { background-color: white; }.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); background-color: rgb(247, 247, 247); white-space: nowrap; }.CodeMirror-linenumbers { }.CodeMirror-linenumber { padding: 0px 3px 0px 5px; text-align: right; color: rgb(153, 153, 153); }.CodeMirror div.CodeMirror-cursor { border-left: 1px solid black; z-index: 3; }.CodeMirror div.CodeMirror-secondarycursor { border-left: 1px solid silver; }.CodeMirror.cm-keymap-fat-cursor div.CodeMirror-cursor { width: auto; border: 0px; background: rgb(119, 238, 119); z-index: 1; }.CodeMirror div.CodeMirror-cursor.CodeMirror-overwrite { }.cm-tab { display: inline-block; }.cm-s-typora-default .cm-header, .cm-s-typora-default .cm-property { color: rgb(217, 79, 138); }.cm-s-typora-default pre.cm-header1:not(.cm-atom) :not(.cm-overlay) { font-size: 2rem; line-height: 2rem; }.cm-s-typora-default pre.cm-header2:not(.cm-atom) :not(.cm-overlay) { font-size: 1.4rem; line-height: 1.4rem; }.cm-s-typora-default .cm-atom, .cm-s-typora-default .cm-number { color: rgb(149, 132, 134); }.cm-s-typora-default .cm-table-row, .cm-s-typora-default .cm-block-start { font-family: monospace; }.cm-s-typora-default .cm-comment, .cm-s-typora-default .cm-code { color: rgb(74, 90, 159); font-family: monospace; }.cm-s-typora-default .cm-tag { color: rgb(169, 68, 66); }.cm-s-typora-default .cm-string { color: rgb(126, 134, 169); }.cm-s-typora-default .cm-link { color: rgb(196, 122, 15); text-decoration: underline; }.cm-s-typora-default .cm-variable-2, .cm-s-typora-default .cm-variable-1 { color: inherit; }.cm-s-typora-default .cm-overlay { font-size: 1rem; font-family: monospace; }.CodeMirror.cm-s-typora-default div.CodeMirror-cursor { border-left: 3px solid rgb(228, 98, 154); }.cm-s-typora-default .CodeMirror-activeline-background { left: -60px; right: -30px; background: rgba(204, 204, 204, 0.2); }.cm-s-typora-default .CodeMirror-gutters { border-right: none; background-color: inherit; }.cm-s-typora-default .cm-trailing-space-new-line::after, .cm-startspace::after, .cm-starttab .cm-tab::after { content: "•"; position: absolute; left: 0px; opacity: 0; font-family: LetterGothicStd, monospace; }.os-windows .cm-startspace::after, .os-windows .cm-starttab .cm-tab::after { left: -0.1em; }.cm-starttab .cm-tab::after { content: " "; }.cm-startspace, .cm-tab, .cm-starttab, .cm-trailing-space-a, .cm-trailing-space-b, .cm-trailing-space-new-line { font-family: monospace; position: relative; }.cm-s-typora-default .cm-trailing-space-new-line::after { content: "↓"; opacity: 0.3; }.cm-s-inner .cm-keyword { color: rgb(119, 0, 136); }.cm-s-inner .cm-atom, .cm-s-inner.cm-atom { color: rgb(34, 17, 153); }.cm-s-inner .cm-number { color: rgb(17, 102, 68); }.cm-s-inner .cm-def { color: rgb(0, 0, 255); }.cm-s-inner .cm-variable { color: black; }.cm-s-inner .cm-variable-2 { color: rgb(0, 85, 170); }.cm-s-inner .cm-variable-3 { color: rgb(0, 136, 85); }.cm-s-inner .cm-property { color: black; }.cm-s-inner .cm-operator { color: rgb(152, 26, 26); }.cm-s-inner .cm-comment, .cm-s-inner.cm-comment { color: rgb(170, 85, 0); }.cm-s-inner .cm-string { color: rgb(170, 17, 17); }.cm-s-inner .cm-string-2 { color: rgb(255, 85, 0); }.cm-s-inner .cm-meta { color: rgb(85, 85, 85); }.cm-s-inner .cm-qualifier { color: rgb(85, 85, 85); }.cm-s-inner .cm-builtin { color: rgb(51, 0, 170); }.cm-s-inner .cm-bracket { color: rgb(153, 153, 119); }.cm-s-inner .cm-tag { color: rgb(17, 119, 0); }.cm-s-inner .cm-attribute { color: rgb(0, 0, 204); }.cm-s-inner .cm-header, .cm-s-inner.cm-header { color: blue; }.cm-s-inner .cm-quote, .cm-s-inner.cm-quote { color: rgb(0, 153, 0); }.cm-s-inner .cm-hr, .cm-s-inner.cm-hr { color: rgb(153, 153, 153); }.cm-s-inner .cm-link, .cm-s-inner.cm-link { color: rgb(0, 0, 204); }.cm-negative { color: rgb(221, 68, 68); }.cm-positive { color: rgb(34, 153, 34); }.cm-header, .cm-strong { font-weight: bold; }.cm-del { text-decoration: line-through; }.cm-em { font-style: italic; }.cm-link { text-decoration: underline; }.cm-error { color: rgb(255, 0, 0); }.cm-invalidchar { color: rgb(255, 0, 0); }.cm-constant { color: rgb(38, 139, 210); }.cm-defined { color: rgb(181, 137, 0); }div.CodeMirror span.CodeMirror-matchingbracket { color: rgb(0, 255, 0); }div.CodeMirror span.CodeMirror-nonmatchingbracket { color: rgb(255, 34, 34); }.cm-s-inner .CodeMirror-activeline-background { background: inherit; }.CodeMirror { position: relative; overflow: hidden; }.CodeMirror-scroll { margin-bottom: -30px; margin-right: -30px; padding-bottom: 30px; padding-right: 30px; height: 100%; outline: none; position: relative; box-sizing: content-box; }.CodeMirror-sizer { position: relative; }.CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler { position: absolute; z-index: 6; display: none; }.CodeMirror-vscrollbar { right: 0px; top: 0px; overflow-x: hidden; overflow-y: scroll; }.CodeMirror-hscrollbar { bottom: 0px; left: 0px; overflow-y: hidden; overflow-x: scroll; }.CodeMirror-scrollbar-filler { right: 0px; bottom: 0px; }.CodeMirror-gutter-filler { left: 0px; bottom: 0px; }.CodeMirror-gutters { position: absolute; left: 0px; top: 0px; padding-bottom: 30px; z-index: 3; }.CodeMirror-gutter { white-space: normal; height: 100%; box-sizing: content-box; padding-bottom: 30px; margin-bottom: -32px; display: inline-block; }.CodeMirror-gutter-elt { position: absolute; cursor: default; z-index: 4; }.CodeMirror-lines { cursor: text; }.CodeMirror pre { border-radius: 0px; border-width: 0px; background: transparent; font-family: inherit; font-size: inherit; margin: 0px; white-space: pre; word-wrap: normal; color: inherit; z-index: 2; position: relative; overflow: visible; }.CodeMirror-wrap pre { word-wrap: break-word; white-space: pre-wrap; word-break: normal; }.CodeMirror-code pre { border-right: 30px solid transparent; width: fit-content; }.CodeMirror-wrap .CodeMirror-code pre { border-right: none; width: auto; }.CodeMirror-linebackground { position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; z-index: 0; }.CodeMirror-linewidget { position: relative; z-index: 2; overflow: auto; }.CodeMirror-widget { }.CodeMirror-wrap .CodeMirror-scroll { overflow-x: hidden; }.CodeMirror-measure { position: absolute; width: 100%; height: 0px; overflow: hidden; visibility: hidden; }.CodeMirror-measure pre { position: static; }.CodeMirror div.CodeMirror-cursor { position: absolute; visibility: hidden; border-right: none; width: 0px; }.CodeMirror div.CodeMirror-cursor { visibility: hidden; }.CodeMirror-focused div.CodeMirror-cursor { visibility: inherit; }.CodeMirror-selected { background: rgb(217, 217, 217); }.CodeMirror-focused .CodeMirror-selected { background: rgb(215, 212, 240); }.cm-searching { background: rgba(255, 255, 0, 0.4); }.CodeMirror span { }@media print {  .CodeMirror div.CodeMirror-cursor { visibility: hidden; }}.CodeMirror-lint-markers { width: 16px; }.CodeMirror-lint-tooltip { background-color: infobackground; border: 1px solid black; border-radius: 4px; color: infotext; font-family: monospace; overflow: hidden; padding: 2px 5px; position: fixed; white-space: pre-wrap; z-index: 10000; max-width: 600px; opacity: 0; transition: opacity 0.4s; font-size: 0.8em; }.CodeMirror-lint-mark-error, .CodeMirror-lint-mark-warning { background-position: left bottom; background-repeat: repeat-x; }.CodeMirror-lint-mark-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAADCAYAAAC09K7GAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB9sJDw4cOCW1/KIAAAAZdEVYdENvbW1lbnQAQ3JlYXRlZCB3aXRoIEdJTVBXgQ4XAAAAHElEQVQI12NggIL/DAz/GdA5/xkY/qPKMDAwAADLZwf5rvm+LQAAAABJRU5ErkJggg=="); }.CodeMirror-lint-marker-error, .CodeMirror-lint-marker-warning { background-position: center center; background-repeat: no-repeat; cursor: pointer; display: inline-block; height: 16px; width: 16px; vertical-align: middle; position: relative; }.CodeMirror-lint-message-error, .CodeMirror-lint-message-warning { padding-left: 18px; background-position: left top; background-repeat: no-repeat; }.CodeMirror-lint-marker-error, .CodeMirror-lint-message-error { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAHlBMVEW7AAC7AACxAAC7AAC7AAAAAAC4AAC5AAD///+7AAAUdclpAAAABnRSTlMXnORSiwCK0ZKSAAAATUlEQVR42mWPOQ7AQAgDuQLx/z8csYRmPRIFIwRGnosRrpamvkKi0FTIiMASR3hhKW+hAN6/tIWhu9PDWiTGNEkTtIOucA5Oyr9ckPgAWm0GPBog6v4AAAAASUVORK5CYII="); }.CodeMirror-lint-marker-warning, .CodeMirror-lint-message-warning { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAANlBMVEX/uwDvrwD/uwD/uwD/uwD/uwD/uwD/uwD/uwD6twD/uwAAAADurwD2tQD7uAD+ugAAAAD/uwDhmeTRAAAADHRSTlMJ8mN1EYcbmiixgACm7WbuAAAAVklEQVR42n3PUQqAIBBFUU1LLc3u/jdbOJoW1P08DA9Gba8+YWJ6gNJoNYIBzAA2chBth5kLmG9YUoG0NHAUwFXwO9LuBQL1giCQb8gC9Oro2vp5rncCIY8L8uEx5ZkAAAAASUVORK5CYII="); }.CodeMirror-lint-marker-multiple { background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAMAAADzjKfhAAAACVBMVEUAAAAAAAC/v7914kyHAAAAAXRSTlMAQObYZgAAACNJREFUeNo1ioEJAAAIwmz/H90iFFSGJgFMe3gaLZ0od+9/AQZ0ADosbYraAAAAAElFTkSuQmCC"); background-repeat: no-repeat; background-position: right bottom; width: 100%; height: 100%; }html { font-size: 14px; background-color: rgb(255, 255, 255); color: rgb(51, 51, 51); }body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; font-size: 1rem; line-height: 1.42857; overflow-x: hidden; background: inherit; }a:active, a:hover { outline: 0px; }.in-text-selection, ::selection { background: rgb(181, 214, 252); text-shadow: none; }#write { margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; padding-bottom: 70px; white-space: pre-wrap; overflow-x: auto; }.for-image #write { padding-left: 8px; padding-right: 8px; }body.typora-export { padding-left: 30px; padding-right: 30px; }@media screen and (max-width: 500px) {  body.typora-export { padding-left: 0px; padding-right: 0px; }  .CodeMirror-sizer { margin-left: 0px !important; }  .CodeMirror-gutters { display: none !important; }}.typora-export #write { margin: 0px auto; }#write > p:first-child, #write > ul:first-child, #write > ol:first-child, #write > pre:first-child, #write > blockquote:first-child, #write > div:first-child, #write > table:first-child { margin-top: 30px; }#write li > table:first-child { margin-top: -20px; }img { max-width: 100%; vertical-align: middle; }input, button, select, textarea { color: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; font-size: inherit; line-height: inherit; font-family: inherit; }input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }::before, ::after, * { box-sizing: border-box; }#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write div, #write pre { width: inherit; }#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6 { position: relative; }h1 { font-size: 2rem; }h2 { font-size: 1.8rem; }h3 { font-size: 1.6rem; }h4 { font-size: 1.4rem; }h5 { font-size: 1.2rem; }h6 { font-size: 1rem; }p { -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }.mathjax-block { margin-top: 0px; margin-bottom: 0px; -webkit-margin-before: 0rem; -webkit-margin-after: 0rem; }.hidden { display: none; }.md-blockmeta { color: rgb(204, 204, 204); font-weight: bold; font-style: italic; }a { cursor: pointer; }#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; margin: 4px 0px 0px; }tr { break-inside: avoid; break-after: auto; }thead { display: table-header-group; }table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; }table.md-table td { min-width: 80px; }.CodeMirror-gutters { border-right: 0px; background-color: inherit; }.CodeMirror { text-align: left; }.CodeMirror-placeholder { opacity: 0.3; }.CodeMirror pre { padding: 0px 4px; }.CodeMirror-lines { padding: 0px; }div.hr:focus { cursor: none; }pre { white-space: pre-wrap; }.CodeMirror-gutters { margin-right: 4px; }.md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background: inherit; position: relative !important; }.md-diagram-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; }.md-fences .CodeMirror.CodeMirror-wrap { top: -1.6em; margin-bottom: -1.6em; }.md-fences.mock-cm { white-space: pre-wrap; }.show-fences-line-number .md-fences { padding-left: 0px; }.show-fences-line-number .md-fences.mock-cm { padding-left: 40px; }.footnotes { opacity: 0.8; font-size: 0.9rem; padding-top: 1em; padding-bottom: 1em; }.footnotes + .footnotes { margin-top: -1em; }.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background: transparent; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; -webkit-tap-highlight-color: transparent; line-height: normal; font-weight: normal; text-align: left; box-sizing: content-box; direction: ltr; }li div { padding-top: 0px; }blockquote { margin: 1rem 0px; }li p, li .mathjax-block { margin: 0.5rem 0px; }li { margin: 0px; position: relative; }blockquote > :last-child { margin-bottom: 0px; }blockquote > :first-child { margin-top: 0px; }.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; }@media print {  html, body { height: 100%; }  .typora-export * { -webkit-print-color-adjust: exact; }  h1, h2, h3, h4, h5, h6 { break-after: avoid-page; orphans: 2; }  p { orphans: 4; }  html.blink-to-pdf { font-size: 13px; }  .typora-export #write { padding-left: 1cm; padding-right: 1cm; }  .typora-export #write::after { height: 0px; }  @page { margin: 20mm 0mm; }}.footnote-line { margin-top: 0.714em; font-size: 0.7em; }a img, img a { cursor: pointer; }pre.md-meta-block { font-size: 0.8rem; min-height: 2.86rem; white-space: pre-wrap; background: rgb(204, 204, 204); display: block; overflow-x: hidden; }p .md-image:only-child { display: inline-block; width: 100%; text-align: center; }#write .MathJax_Display { margin: 0.8em 0px 0px; }.mathjax-block { white-space: pre; overflow: hidden; width: 100%; }p + .mathjax-block { margin-top: -1.143rem; }.mathjax-block:not(:empty)::after { display: none; }[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: none; box-shadow: none; }.task-list { list-style-type: none; }.task-list-item { position: relative; padding-left: 1em; }.task-list-item input { position: absolute; top: 0px; left: 0px; }.math { font-size: 1rem; }.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-radius: 10px; }.md-toc-content { position: relative; margin-left: 0px; }.md-toc::after, .md-toc-content::after { display: none; }.md-toc-item { display: block; color: rgb(65, 131, 196); text-decoration: none; }.md-toc-inner:hover { }.md-toc-inner { display: inline-block; cursor: pointer; }.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: bold; }.md-toc-h2 .md-toc-inner { margin-left: 2em; }.md-toc-h3 .md-toc-inner { margin-left: 4em; }.md-toc-h4 .md-toc-inner { margin-left: 6em; }.md-toc-h5 .md-toc-inner { margin-left: 8em; }.md-toc-h6 .md-toc-inner { margin-left: 10em; }@media screen and (max-width: 48em) {  .md-toc-h3 .md-toc-inner { margin-left: 3.5em; }  .md-toc-h4 .md-toc-inner { margin-left: 5em; }  .md-toc-h5 .md-toc-inner { margin-left: 6.5em; }  .md-toc-h6 .md-toc-inner { margin-left: 8em; }}a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; }.footnote-line a:not(.reversefootnote) { color: inherit; }.md-attr { display: none; }.md-fn-count::after { content: "."; }.md-tag { opacity: 0.5; }.md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: monospace; }code { text-align: left; }h1 .md-tag, h2 .md-tag, h3 .md-tag, h4 .md-tag, h5 .md-tag, h6 .md-tag { font-weight: initial; opacity: 0.35; }a.md-print-anchor { border-width: initial !important; border-style: none !important; border-color: initial !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: none !important; background: transparent !important; text-decoration: initial !important; text-shadow: initial !important; }.md-inline-math .MathJax_SVG .noError { display: none !important; }.mathjax-block .MathJax_SVG_Display { text-align: center; margin: 1em 0em; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; display: block !important; }.MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; }.MathJax_SVG .MJX-monospace { font-family: monospace; }.MathJax_SVG .MJX-sans-serif { font-family: sans-serif; }.MathJax_SVG { display: inline; font-style: normal; font-weight: normal; line-height: normal; zoom: 90%; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; }.MathJax_SVG * { transition: none; }@font-face { font-family: "Open Sans"; font-style: normal; font-weight: normal; src: local("Open Sans Regular"), url("./github/400.woff") format("woff"); }@font-face { font-family: "Open Sans"; font-style: italic; font-weight: normal; src: local("Open Sans Italic"), url("./github/400i.woff") format("woff"); }@font-face { font-family: "Open Sans"; font-style: normal; font-weight: bold; src: local("Open Sans Bold"), url("./github/700.woff") format("woff"); }@font-face { font-family: "Open Sans"; font-style: italic; font-weight: bold; src: local("Open Sans Bold Italic"), url("./github/700i.woff") format("woff"); }html { font-size: 16px; }body { font-family: "Open Sans", "Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; color: rgb(51, 51, 51); line-height: 1.6; }#write { max-width: 860px; margin: 0px auto; padding: 20px 30px 100px; }#write > ul:first-child, #write > ol:first-child { margin-top: 30px; }body > :first-child { margin-top: 0px !important; }body > :last-child { margin-bottom: 0px !important; }a { color: rgb(65, 131, 196); }h1, h2, h3, h4, h5, h6 { position: relative; margin-top: 1rem; margin-bottom: 1rem; font-weight: bold; line-height: 1.4; cursor: text; }h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { text-decoration: none; }h1 tt, h1 code { font-size: inherit; }h2 tt, h2 code { font-size: inherit; }h3 tt, h3 code { font-size: inherit; }h4 tt, h4 code { font-size: inherit; }h5 tt, h5 code { font-size: inherit; }h6 tt, h6 code { font-size: inherit; }h1 { padding-bottom: 0.3em; font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid rgb(238, 238, 238); }h2 { padding-bottom: 0.3em; font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid rgb(238, 238, 238); }h3 { font-size: 1.5em; line-height: 1.43; }h4 { font-size: 1.25em; }h5 { font-size: 1em; }h6 { font-size: 1em; color: rgb(119, 119, 119); }p, blockquote, ul, ol, dl, table { margin: 0.8em 0px; }li > ol, li > ul { margin: 0px; }hr { height: 4px; padding: 0px; margin: 16px 0px; background-color: rgb(231, 231, 231); border-width: 0px 0px 1px; border-style: none none solid; border-top-color: initial; border-right-color: initial; border-left-color: initial; border-image: initial; overflow: hidden; box-sizing: content-box; border-bottom-color: rgb(221, 221, 221); }body > h2:first-child { margin-top: 0px; padding-top: 0px; }body > h1:first-child { margin-top: 0px; padding-top: 0px; }body > h1:first-child + h2 { margin-top: 0px; padding-top: 0px; }body > h3:first-child, body > h4:first-child, body > h5:first-child, body > h6:first-child { margin-top: 0px; padding-top: 0px; }a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 { margin-top: 0px; padding-top: 0px; }h1 p, h2 p, h3 p, h4 p, h5 p, h6 p { margin-top: 0px; }li p.first { display: inline-block; }ul, ol { padding-left: 30px; }ul:first-child, ol:first-child { margin-top: 0px; }ul:last-child, ol:last-child { margin-bottom: 0px; }blockquote { border-left: 4px solid rgb(221, 221, 221); padding: 0px 15px; color: rgb(119, 119, 119); }blockquote blockquote { padding-right: 0px; }table { padding: 0px; word-break: initial; }table tr { border-top: 1px solid rgb(204, 204, 204); background-color: white; margin: 0px; padding: 0px; }table tr:nth-child(2n) { background-color: rgb(248, 248, 248); }table tr th { font-weight: bold; border: 1px solid rgb(204, 204, 204); text-align: left; margin: 0px; padding: 6px 13px; }table tr td { border: 1px solid rgb(204, 204, 204); text-align: left; margin: 0px; padding: 6px 13px; }table tr th:first-child, table tr td:first-child { margin-top: 0px; }table tr th:last-child, table tr td:last-child { margin-bottom: 0px; }.CodeMirror-gutters { border-right: 1px solid rgb(221, 221, 221); }.md-fences, code, tt { border: 1px solid rgb(221, 221, 221); background-color: rgb(248, 248, 248); border-radius: 3px; font-family: Consolas, "Liberation Mono", Courier, monospace; padding: 2px 4px 0px; font-size: 0.9em; }.md-fences { margin-bottom: 15px; margin-top: 15px; padding: 8px 1em 6px; }.task-list { padding-left: 0px; }.task-list-item { padding-left: 32px; }.task-list-item input { top: 3px; left: 8px; }@media screen and (min-width: 914px) {}@media print {  html { font-size: 13px; }  table, pre { break-inside: avoid; }  pre { word-wrap: break-word; }}.md-fences { background-color: rgb(248, 248, 248); }#write pre.md-meta-block { padding: 1rem; font-size: 85%; line-height: 1.45; background-color: rgb(247, 247, 247); border: 0px; border-radius: 3px; color: rgb(119, 119, 119); margin-top: 0px !important; }.mathjax-block > .code-tooltip { bottom: 0.375rem; }#write > h3.md-focus::before { left: -1.5625rem; top: 0.375rem; }#write > h4.md-focus::before { left: -1.5625rem; top: 0.285714rem; }#write > h5.md-focus::before { left: -1.5625rem; top: 0.285714rem; }#write > h6.md-focus::before { left: -1.5625rem; top: 0.285714rem; }.md-image > .md-meta { border: 1px solid rgb(221, 221, 221); border-radius: 3px; font-family: Consolas, "Liberation Mono", Courier, monospace; padding: 2px 4px 0px; font-size: 0.9em; color: inherit; }.md-tag { color: inherit; }.md-toc { margin-top: 20px; padding-bottom: 20px; }#typora-quick-open { border: 1px solid rgb(221, 221, 221); background-color: rgb(248, 248, 248); }#typora-quick-open-item { background-color: rgb(250, 250, 250); border-color: rgb(254, 254, 254) rgb(229, 229, 229) rgb(229, 229, 229) rgb(238, 238, 238); border-style: solid; border-width: 1px; }#md-notification::before { top: 10px; }.on-focus-mode blockquote { border-left-color: rgba(85, 85, 85, 0.117647); }header, .context-menu, .megamenu-content, footer { font-family: "Segoe UI", Arial, sans-serif; }</style></head><body class="typora-export"><div id="write" class="is-node"><h3><a name="header-c5" class="md-header-anchor "></a>提高网页性能的超实用方法</h3><p>就是这么标题党哇咔咔咔~~</p><p>其实只是突然想总结的一些实用小技巧吧，以后想到什么再补充。</p><h4><a name="header-c11" class="md-header-anchor "></a>一.事件委托</h4><p>经常遇到比如有一列<code>&lt;li&gt;&lt;/li&gt;</code>需要绑定点击事件，想想就很容易：</p><pre class="md-fences mock-cm" style="display:block;position:relative">&lt;ul id=&quot;ul&quot;&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script&gt;var oUl = document.getElementById(&#39;ul&#39;);var aLi = oUl.getElementByTagName(&#39;li&#39;);aLi.addEventListener(&#39;click&#39;,function(){ alert(aLi.innerHTML);})&lt;/script&gt;</pre><p>可是，如果，我有100个li，那是要在100个li都绑定事件监听？</p><p>还是不要吧...</p><p>那么事件委托就可以上场了，顾名思义就是把这些事件委托给别人来做，这个别人一般为它的父元素。</p><pre class="md-fences mock-cm" style="display:block;position:relative">&lt;ul id=&quot;ul&quot;&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;li&gt;&lt;/li&gt;&lt;/ul&gt;&lt;script&gt;var oUl = document.getElementById(&#39;ul&#39;);// 事件侦听器绑定到整个容器上  oUl.addEventListener(&#39;click&#39;, function(e) {    if (e.target &amp;&amp; e.target.nodeName === &#39;LI&#39;) {      var aLi = e.target;      alert(aLi.innerHTML);    }  });&lt;/script&gt;</pre><p>jquery的事件委托可以参考我的另一篇博文:<a href="http://anchen1204.github.io/jqcli.html" target="_blank">http://anchen1204.github.io/jqcli.html</a></p><p></p><h4><a name="header-c26" class="md-header-anchor "></a>二.函数防抖</h4><p>window对象的resize、scroll事件，文字输入、自动完成的keyup事件，拖拽时的mousemove事件，它们有个共同点：会频繁地被触发，超乎你的想象。结果可能严重到导致频繁执行DOM操作至浏览器崩溃。</p><p>这个时候就要讨论下这问题了，什么是函数防抖？</p><pre class="md-fences mock-cm" style="display:block;position:relative">// 简单的防抖动函数function debounce(func, wait, immediate) {    // 定时器变量    var timeout;    return function() {        // 每次触发 scroll handler 时先清除定时器        clearTimeout(timeout);        // 指定 xx ms 后触发真正想进行的操作 handler        timeout = setTimeout(func, wait);    };};// 实际想绑定在 scroll 事件上的 handlerfunction realFunc(){    console.log(&quot;Success&quot;);}// 采用了防抖动window.addEventListener(&#39;scroll&#39;,debounce(realFunc,500));// 没采用防抖动window.addEventListener(&#39;scroll&#39;,realFunc);</pre><p>所以，就是500ms 内没有连续触发两次 scroll 事件，那么才会触发我们真正想在 scroll 事件中触发的函数，这就是函数防抖的原理了。</p><h4><a name="header-c34" class="md-header-anchor "></a>三.函数节流</h4><p>上面说了函数防抖，有一种情况可能就有点问题，比如我们下面要讨论的图片懒加载。当然本意并不是希望用户滑到某个点后，停了一段时间，才把他滑过和可视区域的图片加载进来，这是函数防抖的方式就不合适了。</p><p>于是说到函数节流。</p><p>与防抖相比，节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件。</p><pre class="md-fences mock-cm" style="display:block;position:relative">// 简单的节流函数function throttle(func, wait, mustRun) {    var timeout,        startTime = new Date();    return function() {        var context = this,            args = arguments,            curTime = new Date();        clearTimeout(timeout);        // 如果达到了规定的触发时间间隔，触发 handler        if(curTime - startTime &gt;= mustRun){            func.apply(context,args);            startTime = curTime;        // 没达到触发间隔，重新设定定时器        }else{            timeout = setTimeout(func, wait);        }    };};// 实际想绑定在 scroll 事件上的 handlerfunction realFunc(){    console.log(&quot;Success&quot;);}// 采用了节流函数window.addEventListener(&#39;scroll&#39;,throttle(realFunc,500,1000));</pre><p>所以，就算500ms 内连续触发n次 scroll 事件，但保证我们的事件在1000ms内还是会被处理一次，这就是节流函数的原理啦。</p><p>关于以上两点的可见：<a href="http://www.codeceo.com/article/web-high-performance-scroll.html" target="_blank">http://www.codeceo.com/article/web-high-performance-scroll.html</a></p><p></p><p>另外补充一下，有个神奇的css属性叫<code>pointer-events: none</code></p><p>之前用到的场景是头部有个酷炫的canvas动画，然后下面有优惠券需要点击，于是乎把canvas动画层设置这个属性，鼠标对页面的操作就不受到影响啦。</p><p>发现天猫首页滚动时，给body也加了这个属性，这是为了防止你的鼠标在滚动的时候停在页面上，会不断触发页面元素可能绑定的hover事件。</p><p>关于这个属性更多的文章：<a href="http://www.zhangxinxu.com/wordpress/2014/01/pointer-events-none-avoiding-unnecessary-paints/" target="_blank">http://www.zhangxinxu.com/wordpress/2014/01/pointer-events-none-avoiding-unnecessary-paints/</a></p><p>另外，张大大还有另一篇讲关于这个属性对性能的提升讨论：<a href="http://www.zhangxinxu.com/wordpress/2014/01/pointer-events-none-avoiding-unnecessary-paints/" target="_blank">http://www.zhangxinxu.com/wordpress/2014/01/pointer-events-none-avoiding-unnecessary-paints/</a> ，非常有趣，值得一读，也值得去实践。</p><h4><a name="header-c58" class="md-header-anchor "></a>四.图片懒加载</h4><p>懒加载就是lazyload(这是一句废话)。比较常见于图片按需加载，几乎很容易就可以在网上找到例子，比如前东家京东的各种页面。当这些资源不在浏览器的可视区域时，先不用加载，等到适当的时候再去加载资源，避免网页打开时间过长，页面load太久影响用户体验。</p><p>实现原理：</p><p>1.为<code>&lt;img&gt;</code>标签设置一个暂存图片URL的自定义属性（例如data-url）存储图片实际地址，图片原本src里用一张1*1或者尺寸小的图统一代替，当图片出现在视口时，再将data-url的值赋给图片的src属性；</p><p>2.怎么判断“适当的时候”，这里只以竖直方向作为判断。</p><ul><li><p>屏幕可视窗口大小：</p><p>原生方法：</p><pre class="md-fences mock-cm" style="display:block;position:relative">window.innerHeight 标准浏览器及IE9+ document.documentElement.clientHeight 标准浏览器及低版本IE标准模式document.body.clientHeight 低版本混杂模式</pre><p>jQuery方法： <code>$(window).height()</code></p></li><li><p>浏览器窗口顶部与文档顶部之间的距离，也就是滚动条滚动的距离</p><p>原生方法：</p><pre class="md-fences mock-cm" style="display:block;position:relative">window.pagYoffset——IE9+及标准浏览器 document.documentElement.scrollTop 兼容ie低版本的标准模式document.body.scrollTop 兼容混杂模式； </pre><p>jQuery方法：<code>$(document).scrollTop();</code></p></li><li><p>获取元素的位置信息</p><p>jQuery：<code>$(o).offset().top</code>元素距离文档顶的距离</p></li><li><p>判断元素进入可视区域</p><p>元素在文档的高度跟浏览器窗口与（滚动条的高度+屏幕可视窗口的高度）相等即进入可视区域。</p></li></ul><p>分享个插件<a href="http://www.appelsiini.net/projects/lazyload" target="_blank">http://www.appelsiini.net/projects/lazyload</a></p><h4><a name="header-c96" class="md-header-anchor "></a>五.图片预加载</h4><p>预加载就是与懒加载相反的东西(这不是废话)。它是牺牲服务器前端性能来换取更好的用户体验，字面意思就是浏览器把图片下到本地，同样的src就会使用缓存。</p><pre class="md-fences mock-cm" style="display:block;position:relative">function loadImage(url,callback) {    var img = new Image();        img.src = url;    img.onload = function(){        img.onload = null;        callback.call(img);    }}</pre><p>使用场景比如，头部动画元素较多或者有某个比较大，需要让图片预加载，以免影响动画效果，相信也不希望动画在播放的同时图片还在load吧。</p><p>比如我其中一个项目这么写：</p><pre class="md-fences mock-cm" style="display:block;position:relative">/*头部动画图片预加载*/    function preLoad(){        var  iCount=0,          img1 = new Image(),          img2 = new Image(),          img3 = new Image(),          img4 = new Image(),          img5 = new Image(),          img6 = new Image();        var arr = [img1,img2,img3,img4,img5,img6];        for(var i=0;i&lt;arr.length;i++){            arr[i].onload=function(){                iCount++;                if(iCount==6){                   $(&#39;.banner&#39;).addClass(&#39;ani-banner&#39;);                }            }        }        img1.src=&#39;地址&#39;;        img2.src=&#39;地址&#39;;        img3.src=&#39;地址&#39;;        img4.src=&#39;地址&#39;;        img5.src=&#39;地址&#39;;        img6.src=&#39;地址&#39;;    }$(function(){    preLoad();});</pre><p></p><h4><a name="header-c107" class="md-header-anchor "></a>六.重排和重绘（reflow和repaint）</h4><p>首先复习一下浏览器中访问一个网址的页面呈现过程：</p><p>1.浏览器首先获取html页面；</p><p>2然后解析它的Dom结构；</p><p>3.接着解析css（css+Dom每个节点的位置和大小等几何信息，layout）；</p><p>4.css paint（绘制成位图）；</p><p>5.传输到GPU渲染到屏幕。</p><p>重排和重绘就发生在第3和第4步。</p><p>所以，在解析css开始的步骤，修改的css元素是在越前的步骤解析的话会越耗性能，因为它及其它后面的步骤将会被重新修改一遍。 换句话来说，Dom操作触发频繁reflow（layout）和repaint，layout发生在repaint之前，相对会造成更多性能损坏。</p><p>那么，哪些元素会影响layout和paint？</p><p>举些我们很常用的例子：</p><p>影响layout： margin/padding/width/height/display/border/top/left/right/bottom/position/font-size/text-align/line-height/font-weight/font-family/overflow...</p><p>影响repaint： </p><p>color/border-style/visibility/backgrounf/text-decoration/border-radius/outline/box-shadow/backgrounf-size...</p><p>注意：</p><p>设置动画元素为absolute或fixed：</p><ul><li>position:static或position:relative元素应用动画效果会造成频繁的reflow。</li><li>position:absolute或position:fixed的元素应用动画效果只需要repaint.</li></ul><p></p><p></p><h4><a name="header-c147" class="md-header-anchor "></a>七.css3动画性能优化</h4><p>竟然被问住了，然后十分钟之后想起来我....</p><p>也写在这里吧，之前有探讨过一篇<a href="http://anchen1204.github.io/webs.html" target="_blank" rel="noopener">关于web渲染及硬件加速</a>，其实就有提到动画性能的问题。</p><p>曾经遇到一个移动端问题，做的一个蝴蝶节活动，有比较多的入场的动画，然后做好后设计觉得可以更花哨，要求加上一大两小三只蝴蝶在循环infinite动画，我觉得会比较耗性能阻止未果后，还是加上去。</p><p>然后测试上线时，6p微信崩了..。</p><p>后来，动画不能砍，设计会跟我拼命，所以我只能再看看。</p><p>检查是不是我的dom尺寸太大导致绘制时造成内存的溢出...</p><p>把蝴蝶的循环位移left啊这些位移直接交给translate3d来做，开启硬件加速，但是不能滥用，会耗电...</p><p>检查动画是否占文档流，是的话改为绝对定位，减少重排和重绘...</p><p>把图片重新再压缩一遍...</p><p>...其他还做了什么我忘了，最后没啥问题了</p><p></p><p>另外，如果需要些js动画的，一般会用setTimeout,但是还有另外一个为动画而生的，叫requestAnimationFrame，比如<a href="http://anchen1204.github.io/demo/spball/ball-10.html" target="_blank">http://anchen1204.github.io/demo/spball/ball-10.html</a>，这里就使用了这个东西。好处在于setTimeout可能会出现掉帧卡顿现象，因为它在js内执行，js是单线程可能会有阻塞。而requestAnimationFrame相当于是把动画交给浏览器去执行，浏览器会基于当前页面情况来自行决定最佳的帧速率，从而更合理地使用CPU。但是，它兼容Android4.4及以上，IE10及以上，兼容性其实跟css3动画差不多，所以可能要根据需求配合setTimeout做降级处理。</p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p></p><p>未完待续...</p><p>​</p><p></p><p></p><p></p></div></body></html>]]></content>
    
    <summary type="html">
    
      
      
        &lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;&lt;meta name=&quot;generator&quot; content=&quot;Hexo 3.8.0&quot;&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;&lt;meta name=&quot;viewport&quot; content=&quot;width=device-
      
    
    </summary>
    
    
      <category term="webs" scheme="http://yoursite.com/tags/webs/"/>
    
  </entry>
  
  <entry>
    <title>socket.io</title>
    <link href="http://yoursite.com/2017/03/08/socket-io/"/>
    <id>http://yoursite.com/2017/03/08/socket-io/</id>
    <published>2017-03-08T11:17:04.000Z</published>
    <updated>2018-06-12T12:00:02.000Z</updated>
    
    <content type="html"><![CDATA[<p>最近在看socket.io，想理一理思绪。</p><p>先丢一堆问题：</p><ul><li>什么是WebSocket？有什么用？</li><li>什么是socket.io，跟WebSocket的关系？</li><li>socket跟Ajax的区别？</li><li>怎么使用socket.io?</li></ul><h2 id="WebSocket"><a href="#WebSocket" class="headerlink" title="WebSocket"></a>WebSocket</h2><p>WebSocket是对在服务器和客户端之间实现双向实时通信问题的响应。就是在web服务器和浏览器之间保持持久打开，相当于建了一座桥，让两边的信息可以随时推送数据。它的核心就是“实时”。</p><h2 id="Socket-IO"><a href="#Socket-IO" class="headerlink" title="Socket.IO"></a>Socket.IO</h2><p>socket.io是NodeJs的一个模块，为了可以方便使用WebSocket问题。它提供服务器和浏览器之间的响应的组件，只需要一个模块就可以给应用程序加入对WebSocket的支持，并且，Socket.IO支持4种协议：WebSocket、htmlfile、xhr-polling、jsonp-polling，它会自动根据浏览器选择适合的通讯方式，也因此可以解决浏览器对WebSocket的支持问题。</p><p>总而言之，它可以很方便构建支持WebSocket的模块，把应用程序实时通信变得简单，而且几乎可以支持所有常用的浏览器实现。</p><p>它跟Ajax的区别在于，它提供的功能更多，比如很容易实时地将数据推送给客户端。并且WebSocket的一大特性就是实时连接，这是持久的过程，而Ajax则是每次都需要建立连接。</p><p>但是它们的服务目标也是不同，所以并不能说就只用socket。Ajax适合只需要时不时请求一下数据，并且可能需要缓冲的场景。</p><h2 id="聊天室例子"><a href="#聊天室例子" class="headerlink" title="聊天室例子"></a>聊天室例子</h2><p>通过例子来学习是最快的理解方式，这里选了一个聊天室的例子。</p><p><strong>安装</strong></p><p>服务器端使用socket.io:</p><p>nodejs服务器端安装：npm install socket.io<br>安装之后就可以require模块来使用了:</p><p><code>var io = require(&#39;socket.io&#39;);</code></p><p>客户端安装直接在页面想引用外部链js那样即可：<code>&lt;script src=&quot;/socket.io/socket.io.js&quot;&gt;&lt;/script&gt;</code></p><p><strong>思路</strong></p><p>聊天室的逻辑点其实很简单，就是进入房间，开聊，退出房间。</p><p><strong>构建</strong></p><p>案例参考文章<a href="[http://www.jianshu.com/p/40d8bc17529f](http://www.jianshu.com/p/40d8bc17529f">socket.io+express多房间聊天应用</a>))</p><p>这个案例很容易了解socket.io的原理，帮助我更好地理解。</p><p>原demo有些bug，比如在线用户昵称不显示（room.hbs）：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">// 监听系统消息</span><br><span class="line">      socket.on(&apos;sys&apos;, function (sysMsg, users) &#123;</span><br><span class="line">        var message = &apos;&lt;div class=&quot;sysMsg&quot;&gt;&apos; + sysMsg + &apos;&lt;/div&gt;&apos;;</span><br><span class="line">        $(&apos;#msglog&apos;).append(message);</span><br><span class="line"></span><br><span class="line">        $(&apos;#count&apos;).text(users.length);</span><br><span class="line">        $(&apos;#users&apos;).text(users);</span><br><span class="line">      &#125;);</span><br></pre></td></tr></table></figure><p>原因是users打印出来其实是数组，并不能直接text显示在页面上，需要改为</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">var userArray= users.join(&quot;,&quot;);</span><br><span class="line"></span><br><span class="line"> $(&apos;#users&apos;).text(userArray);</span><br></pre></td></tr></table></figure><p>另外css样式是直接写在room.hbs里的，不方便拓展，所以我把它提出来, 在public里新建css文件夹，style.css。</p><p>room.hbs引用<code>&lt;link rel=&quot;stylesheet&quot; href=&quot;/css/style.css&quot;&gt;</code></p><p>在app.js中说明引用静态资源目录：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">//静态资源目录</span><br><span class="line"></span><br><span class="line">app.use(express.static(&apos;public&apos;));</span><br></pre></td></tr></table></figure><h2 id="socket-io事件"><a href="#socket-io事件" class="headerlink" title="socket.io事件"></a>socket.io事件</h2><p><a href="http://www.cnblogs.com/xiezhengcai/p/3956401.html" target="_blank" rel="noopener">socket中文手册</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;最近在看socket.io，想理一理思绪。&lt;/p&gt;
&lt;p&gt;先丢一堆问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;什么是WebSocket？有什么用？&lt;/li&gt;
&lt;li&gt;什么是socket.io，跟WebSocket的关系？&lt;/li&gt;
&lt;li&gt;socket跟Ajax的区别？&lt;/li&gt;
&lt;
      
    
    </summary>
    
    
      <category term="socket" scheme="http://yoursite.com/tags/socket/"/>
    
  </entry>
  
  <entry>
    <title>canvas Api</title>
    <link href="http://yoursite.com/2017/01/12/canvas-Api/"/>
    <id>http://yoursite.com/2017/01/12/canvas-Api/</id>
    <published>2017-01-12T11:55:12.000Z</published>
    <updated>2018-06-12T12:01:10.000Z</updated>
    
    <content type="html"><![CDATA[<!DOCTYPE html><html lang="en"><head><meta name="generator" content="Hexo 3.8.0"><meta charset="UTF-8"><title>canvas API</title><script src="http://acen.jd.com/h5/topActivity/media/js/lib/zepto-1.1.6.min.js"></script><style>.wrapper{width: 1000px;margin: 0 auto}p{font-size: 20px;line-height: 1.5;color: #333333}pre{background: #f7f7f9;height: 100%;line-height: 2;font-size: 20px;color: #333333}h2{font-size: 34px}h3{font-weight: bold;font-size: 26px}#sevenb{width: 300px;height: 300px;}#changec{width: 300px;height: 300px;}</style></head><body><div class="nav"></div><div class="wrapper"><h2>准备</h2><h3>一.width和height</h3><pre><code> &lt;canvas id="myCanvas" width="666" height="666" &gt; &lt;/canvas&gt; </code></pre><p>这里的width和height指实际像素宽高，我们也可以理解为是canvas的分辨率，按标准不带单位， <strong>与在css里面定义是两种东西：</strong></p><p>1.从js来看</p><pre><code>canvas.width=666;canvas.height=666;canvas.style.width="666px"canvas.style.height="666px </code></pre><p>2.从html来看</p><pre><code>&lt;canvas id = "myCanvas" width="300" height="300"&gt;&lt;/canvas&gt;&lt;canvas id = "myCanvas" style="width:300px;height:300px"&gt;&lt;/canvas&gt;</code></pre><p>上面的代码画出来的效果如下：</p><p><img src="http://warm1204.github.io/image/canvasWidth.png" alt=""></p><p>3.总结</p><pre><code>&lt;canvas width="300" height="300" style="width:100px;height="100px"&gt;</code></pre><p>实际上是把一个300x300的canvas画布强制缩放成100px*100px了。canvas本身有一个默认的width和height，一般是300x150</p><br><h3>二.beginPath和closePath</h3><p>beginPath和closePath是绘图过程中必不可少的两个东西，他们完全没有关系</p><br><p>beginPath方法类似于开启新的路径绘画或清空已有路径,会以最接近的上一个beginPath为起点渲染下面的所有绘图</p><pre><code>    context.beginPath()context.moveTo(100,100)context.lineTo(700,700)context.strokeStyle = "#005588"context.stroke()    //context.beginPath()context.moveTo(200,200)context.lineTo(800,800)context.strokeStyle = "#ff6567"context.stroke()    </code></pre><br><p>closePath： 并不是表示结束，它的意思是关闭路径，就是从当前路径的终点连一条路径到起点，让整个路径闭合起来。但是如果没有它，用了fill()内部色填充，也是会如期把可能的闭合路径填上内部色。</p><p>就是说下面的两段代码是一个效果。</p><pre><code>//eg1context.moveTo(100,100)context.lineTo(700,700)context.lineTo(100,700)context.closePath()//eg2context.moveTo(100,100)context.lineTo(700,700)context.lineTo(100,700)context.lineTo(100,100)</code></pre><br><p>综上beginPath和closePath其实是没有关系的~</p><h2>一.基本图形</h2><h3>线</h3><p>绘制一条从当前未知到指定x以及y位置的直线</p><pre><code>lineTo(x,y)</code></pre><p>这里的x和y是代表结束的点坐标，开始点与之前绘制的路径有光，也可以通过moveTo()来改变。</p><br><h3>矩形</h3><p>绘制一个填充的矩形，，注意在使用fillRect绘制矩形时，必须先设置各种样式，否则样式无效（代码顺序 ）</p><pre><code>fillRect(x,y,width,height)</code></pre><br><p>绘制一个矩形边框</p><pre><code>strokeRect(x,y,width,height)</code></pre><br><p>清除矩形区域</p><pre><code>clearRect(x,y,width,height)</code></pre><p>以上xy均指在canvas画布上离左上角原点的坐标</p><br><h3>圆弧</h3><p>arc(圆心坐标，圆心坐标，半径的值，弧线开始于哪个弧度值，结束于哪个弧度值，顺时针或逆时针false为顺时针可选参数)</p><p>0pi在正东方向</p><p> <strong>注意：arc()函数中的角度单位是弧度，不是度数。</strong></p><br><h3>贝塞尔曲线</h3><p>绘制二次贝塞尔曲线，x,y为结束点；cp1x,cp1y为控制点，用于决定该曲线的形状。这个方法所绘制的贝塞尔曲线会将锚点与当前路径最后一个点连接起来。</p><pre><code>quadraticCurveTo(cp1x,cp1y,x,y)</code></pre><br><p>绘制三次贝塞尔曲线，x,y为结束点，cp1x,cp1y为控制点一，cp2x,cp2y为控制点2</p><pre><code>bezierCurveTo(cp1x,cp1y,cp2x,cp2y,x,y))</code></pre><br><canvas id="Beisaier"></canvas><h2>二.样式</h2><h3>colors</h3><p>设置图形的填充颜色</p><pre><code>fillStyle = color</code></pre><br><p>设置图形轮廓的颜色</p><pre><code>strokeStyle = color</code></pre><p>这两个属性除了可以应用颜色外，也可以被设置为渐变色或者图案</p><br><p>应用例子：七巧板</p><canvas id="sevenb"></canvas><br><p>应用例子：调色板</p><canvas id="changec"></canvas><script></script><br><h3>透明度ransparency</h3><pre><code>fillStyle = "rgba(255,0,0,0.5)"</code></pre><pre><code>strokeStyle= "rgba(255,0,0,0.5)</code></pre><br><p>globalAlpha属性（0~1.0）</p><pre><code>context.globalAlpha = 0.2</code></pre><br><h3>渐变</h3><p>创建线性渐变，表示渐变线的两个端点。可以通过addColorStop()方法来向该渐变线增加颜色停止点。</p><pre><code>crearLinearGradient(x1,y1,x2,y2)</code></pre><br><p>创建放射渐变，参数表示位于圆锥形渐变区域两端的圆形。</p><pre><code>createRadialGradient(x1,y1,r1,x2,y2,r2)</code></pre><br><h3>阴影</h3><p>canvas中的阴影主要为以下4个属性所控制：</p><p>1.shadowColor:css3格式的颜色；</p><p>2.shadowOffsetX:从图形或者文本到阴影的水平像素偏移，可为负整数</p><p>3.shadowOffsetY</p><p>4.shadowBlur：与像素无关，用于设定阴影的模糊程度，也不受变换矩阵的影响，默认为 0</p><br><canvas id="Shadow"></canvas><h2>三.文本</h2><p>文本的填充</p><pre><code>fillText(text,x,y,[可选]最大宽度)</code></pre><br><p>绘制文本边框</p><pre><code>strokeText(text,x,y，[可选]最大宽度) </code></pre><br><p>样式：</p><pre><code>context.font="10px sans-serif" //默认值，字体大小和字体类型，必填</code></pre><pre><code>textAlign = value //基线水平对齐选项. 可选的值包括：start,left,center,right,end。默认值是 start</code></pre><pre><code>textBaseline = value  //基线竖直对齐选项. 可选的值包括：top, hanging, middle, alphabetic, ideographic, bottom。默认值是 alphabetic</code></pre><pre><code>direction = value //文本方向。可能的值包括：ltr, rtl, inherit。默认值是 inherit。</code></pre><br><pre><code>measureText(text)</code></pre><br><h2>四.图案</h2><p>fillStyle和strokeStyle除了可用渐变色和颜色，还可以用图案来描边或者填充</p><br><pre><code>creatPattern(image,type)</code></pre><p>type可取以下值：repeat ,repeat-x,repeat-y,no-repeat,道理同css里的background，用法跟渐变很类似的，创建出一个 pattern 之后，赋给 fillStyle 或 strokeStyle 属性即可</p><pre><code>var img = new Image(); img.src = 'someimage.png';var ptrn = context.createPattern(img,'repeat'); </code></pre><br><p>Image()函数</p><pre><code>var img = new Image();    img.onload=function(){      ctx.drawImage(img,50,50,51,51)    }    img.src = 'redball.png'    //img.src="Base64"    </code></pre><br><h2>五.其他</h2><h3>save()&restore()</h3><p>save 和 restore 方法是用来保存和恢复 canvas 状态的，都没有参数。Canvas 的状态就是当前画面应用的所有样式和变形的一个快照。</p><p>Canvas状态存储在栈中，每当save()方法被调用后，当前的状态就被推送到栈中保存，可以任意次使用save(),每一次调用 restore 方法，上一个保存的状态就从栈中弹出，所有设定都恢复。</p><pre><code>context.save();context.restore();</code></pre><br><h3>globalCompositeOperation</h3><pre><code>globalCompositeOperation = type</code></pre><p>type有12种取值，比如以下：</p><p>source-over ：默认，新图形覆盖在原有图形之上</p><p>destination-over：与上面相反</p><p>source-in：仅出现新图形中与老图形重叠的部分，其余透明</p><p>source-atop：新图形中与原有内容重叠的部分会被绘制，并覆盖于原有内容之上。</p><p>copy：新图形会被保留，其余清除</p><p>...</p><br><h3>Clipping paths</h3><pre><code>clip():用法与stroke()和fill() 类似</code></pre><pre><code>   ctx.beginPath();  ctx.arc(0,0,60,0,Math.PI*2,true);  ctx.clip();  </code></pre><br><h3>getImageData()& putImageData</h3><p>getImageData() 方法返回 ImageData 对象，该对象拷贝了画布指定矩形的像素数据。</p><pre><code>context.getImageData(x,y,width,height);</code></pre><br><p>putImageData(imgData,x,y):把getImageData()得到的像素数据展现出来</p><br><p>demo:</p><img id="scream" src="http://warm1204.github.io/image/people.jpg"><canvas id="getImage" width="390" height="480"></canvas><script>document.getElementById("scream").onload=function(){  var c=document.getElementById("getImage");  var ctx=c.getContext("2d");  var img=document.getElementById("scream");  ctx.drawImage(img,0,0);  var imgData=ctx.getImageData(0,0,c.width,c.height);  // invert colors  for (var i=0;i<imgData.data.length;i+=4)    {    imgData.data[i]=255-imgData.data[i];    imgData.data[i+1]=255-imgData.data[i+1];    imgData.data[i+2]=255-imgData.data[i+2];    imgData.data[i+3]=255;    }  ctx.putImageData(imgData,0,0);}</script><br><h3>canvas.toDataURL(MIME)</h3><p>上面介绍了把图片导入／转化为canvas，那么canvas画布也可以转为图片，需要一个toDataURL()方法,因为在canvas中绘出的图片只是canvas标签而已，并非是真正的图片，是不能右键另存为的</p><pre><code>var image = new Image(); image.src = canvas.toDataURL("image/png");</code></pre><p>canvas.toDataURL 返回的是一串Base64编码的URL</p><br><br><p>demo:简易画板</p><div align="center"><canvas id="myCanvas" width="500" height="400" style="border:2px solid #6699cc"></canvas><div class="control-ops"><button type="button" class="btn btn-primary" onclick="javascript:clearArea();return false;">清空画板</button>Line width :<select id="selWidth"><option value="1">1</option><option value="3">3</option><option value="5">5</option><option value="7">7</option><option value="9" selected="selected">9</option><option value="11">11</option></select>Color :<select id="selColor"><option value="black">black</option><option value="blue" selected="selected">blue</option><option value="red">red</option><option value="green">green</option><option value="yellow">yellow</option><option value="gray">gray</option></select><button type="button" class="btn btn-primary" onclick="javascript:clipCanvas();return false;">pictureCut</button></div></div><script>    var mousePressed = false;var lastX, lastY;var ctx;var canvas = document.getElementById('myCanvas');function InitThis() {    ctx = document.getElementById('myCanvas').getContext("2d");     $('#myCanvas').mousedown(function (e) {        mousePressed = true;        Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, false);    });     $('#myCanvas').mousemove(function (e) {        if (mousePressed) {            Draw(e.pageX - $(this).offset().left, e.pageY - $(this).offset().top, true);        }    });     $('#myCanvas').mouseup(function (e) {        mousePressed = false;    });        $('#myCanvas').mouseleave(function (e) {        mousePressed = false;    });} function Draw(x, y, isDown) {    if (isDown) {        ctx.beginPath();        ctx.strokeStyle = $('#selColor').val();        ctx.lineWidth = $('#selWidth').val();        ctx.lineJoin = "round";        ctx.moveTo(lastX, lastY);        ctx.lineTo(x, y);        ctx.closePath();        ctx.stroke();    }    lastX = x; lastY = y;}     function clearArea() {    // Use the identity matrix while clearing the canvas    ctx.setTransform(1, 0, 0, 1, 0, 0);    ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);}  function clipCanvas(){ var image = canvas.toDataURL("image/png");       var w=window.open('about:blank','image from canvas');       w.document.write("<img src='"+image+"' alt='from canvas'/>");      console.log(image.substr(22))    /*var image = new Image();  image.src = canvas.toDataURL("image/png"); */}$(function(){    InitThis();    })</script></div><script>//七巧板var tangram=[{p:[{x:0,y:0},{x:800,y:0},{x:400,y:400}],color:"#caff67"},{p:[{x:0,y:0},{x:400,y:400},{x:0,y:800}],color:"#67beef"},{p:[{x:800,y:0},{x:800,y:400},{x:600,y:600},{x:600,y:200}],color:"#cf3d61"},{p:[{x:600,y:200},{x:600,y:600},{x:400,y:400}],color:"#f9f51a"},{p:[{x:400,y:400},{x:600,y:600},{x:400,y:800},{x:200,y:600}],color:"#a594c0"},{p:[{x:200,y:600},{x:400,y:800},{x:0,y:800}],color:"#fa8ccc"},{p:[{x:800,y:400},{x:800,y:800},{x:400,y:800}],color:"#f6ca29"},]function SevenColor(){var cvs = document.getElementById('sevenb');var context = cvs.getContext('2d');cvs.width = 800;cvs.height = 800;for(var i = 0 ;i < tangram.length;i++){draw(tangram[i],context)}function draw(piece,cxt){cxt.beginPath();cxt.moveTo(piece.p[0].x,piece.p[0].y);for(var i=1;i<piece.p.length;i++){cxt.lineTo(piece.p[i].x, piece.p[i].y);/*cxt.closePath();beginPath方法类似于开启新的路径绘画或清空已有路径 而closePath并不是用来表示结束 而是功能性的 做图形闭合处理（从最后的状态点自动lineTo回归起始点封口）所以加上这句七巧板会被分割更多块*/}cxt.fillStyle = piece.color;cxt.fill();cxt.lineWidth =3;cxt.stroke();}}//调色板function changeColor(){var cvs = document.getElementById('changec');var ctx = cvs.getContext('2d');cvs.width = 600;cvs.height = 600;  for (var i=0;i<6;i++){    for (var j=0;j<6;j++){      ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' +                     Math.floor(255-42.5*j) + ',0)';      ctx.fillRect(j*100,i*100,100,100);    }  }}//阴影function shadow(){var cvs = document.getElementById('Shadow');cvs.width = 400;cvs.height = 400;   function wshadow(){   ctx.beginPath();     ctx.shadowOffsetX = 10;  ctx.shadowOffsetY = 10;  ctx.shadowBlur = 10;  ctx.shadowColor = "rgba(0, 0, 0, 0.5)";    ctx.fillStyle="rgba(255,0,0,0.5)";    ctx.fillRect(10,10,100,100);    }      function nshadow(){      ctx.beginPath();     ctx.shadowOffsetX = -10;  ctx.shadowOffsetY = -10;  ctx.shadowBlur = 10;  ctx.shadowColor = "rgba(0, 0, 0, 0.5)";    ctx.fillStyle="rgba(255,0,0,0.5)";    ctx.fillRect(10,210,100,100);    }  if (cvs.getContext){    var ctx = cvs.getContext('2d');    wshadow()   nshadow()     }}//贝塞尔曲线function Beisaier(){var canvas = document.getElementById('Beisaier')var ctx = canvas.getContext('2d');        //三次曲线    ctx.beginPath();    ctx.moveTo(75,40);    ctx.bezierCurveTo(75,37,70,25,50,25);    ctx.bezierCurveTo(20,25,20,62.5,20,62.5);    ctx.bezierCurveTo(20,80,40,102,75,120);    ctx.bezierCurveTo(110,102,130,80,130,62.5);    ctx.bezierCurveTo(130,62.5,130,25,100,25);    ctx.bezierCurveTo(85,25,75,37,75,40);    ctx.fill();}window.onload=function(){SevenColor();changeColor();shadow();Beisaier();}</script></body></html>]]></content>
    
    <summary type="html">
    
      
      
        
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;&lt;meta name=&quot;generator&quot; content=&quot;Hexo 3.8.0&quot;&gt;
	&lt;meta charset=&quot;UTF-8&quot;&gt;
	&lt;title&gt;canvas API&lt;/title&gt;
	&lt;sc
      
    
    </summary>
    
    
      <category term="canvas" scheme="http://yoursite.com/tags/canvas/"/>
    
  </entry>
  
  <entry>
    <title>webpack使用</title>
    <link href="http://yoursite.com/2016/10/17/webpack%E4%BD%BF%E7%94%A8/"/>
    <id>http://yoursite.com/2016/10/17/webpack使用/</id>
    <published>2016-10-17T11:38:44.000Z</published>
    <updated>2018-07-23T04:10:48.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="webpack有什么用"><a href="#webpack有什么用" class="headerlink" title="webpack有什么用"></a>webpack有什么用</h3><p>可以帮助我们把多个js文件打包为1个入口文件，并且可以按需加载。也就是无需担心太多组件导致过多的http请求。同时webpack也可以编译.vue文件，如果没有使用一个loader去转换我们的.vue文件里的style、js、html，浏览器无法识别。</p><h3 id="模块热加载"><a href="#模块热加载" class="headerlink" title="模块热加载"></a>模块热加载</h3><p>webpack的模块热加载可以为单页应用带来便利，当我们修改代码刷新页面后，应用里所有状态就都没有了，需要再重新跑一次。而模块热加载就是当你修改代码后，页面不会被刷新，状态也可以保留下来。</p><h3 id="一-安装"><a href="#一-安装" class="headerlink" title="一.安装"></a>一.安装</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">//全局安装</span><br><span class="line"></span><br><span class="line">npm install -g webpack</span><br><span class="line"></span><br><span class="line">//安装到你的项目目录</span><br><span class="line"></span><br><span class="line">npm install --save-dev webpack</span><br></pre></td></tr></table></figure><h3 id="二-使用"><a href="#二-使用" class="headerlink" title="二.使用"></a>二.使用</h3><p>1.建立一个空文件夹，暂命名为webpack；</p><p>2.建立一个package.json的的npm说明文件，将用来记录当前项目的依赖模块，自定义脚本任务等。也可以在终端使用<code>npm init</code>自动建立；</p><p><img src="http://upload-images.jianshu.io/upload_images/1031000-976ba1a06fd0702f.png?imageMogr2/auto-orient/strip%7CimageView2/2" alt="">。</p><p>4.文件对应的内容如下：</p><ul><li><strong>index.html</strong>文件只有最基础的html代码，它唯一的目的就是加载打包后的js文件（bundle.js）:</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">&lt;!DOCTYPE html&gt;&lt;html lang=&quot;en&quot;&gt;&lt;head&gt;&lt;meta charset=&quot;utf-8&quot;&gt;&lt;title&gt;Webpack Sample Project&lt;/title&gt;&lt;/head&gt;&lt;body&gt;&lt;div id=&apos;root&apos;&gt;&lt;/div&gt;&lt;script src=&quot;bundle.js&quot;&gt;&lt;/script&gt;&lt;/body&gt;&lt;/html&gt;</span><br></pre></td></tr></table></figure><ul><li><strong>Greeter.js</strong>只包括一个用来返回包含问候信息的html元素的函数。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">// Greeter.jsmodule.exports = function() &#123;</span><br><span class="line">  var greet = document.createElement(&apos;div&apos;);</span><br><span class="line">  greet.textContent = &quot;Hi there and greetings!&quot;;</span><br><span class="line">  return greet;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><ul><li><strong>main.js</strong>用来把Greeter模块返回的节点插入页面。</li></ul><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">//main.js var greeter = require(&apos;./Greeter.js&apos;);</span><br><span class="line">document.getElementById(&apos;root&apos;).appendChild(greeter());</span><br></pre></td></tr></table></figure><p>5.通过配置文件来使用webpack</p><p>在当前的webpack文件夹下新建一个名为webpack.config.js的文件，内容如下(注意entry里的引用写法，这里跟原文有差):</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">module.exports = &#123;</span><br><span class="line"></span><br><span class="line">  entry:  &quot;../webpack/app/main.js&quot;,//已多次提及的唯一入口文件</span><br><span class="line"></span><br><span class="line">  output: &#123;</span><br><span class="line"></span><br><span class="line">    path:  &quot;public&quot;,//打包后的文件存放的地方</span><br><span class="line"></span><br><span class="line">    filename: &quot;bundle.js&quot;//打包后输出文件的文件名</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>6.编译</p><p>在webpack文件夹下打开命令行，输入</p><p><code>webpack</code></p><p>编译成功后打开index.html就可以看到内容。</p><p><em>7.更快捷的打包方式</em></p><p>在package.json里进行配置：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  &quot;name&quot;: &quot;package&quot;,</span><br><span class="line">  &quot;version&quot;: &quot;1.0.0&quot;,</span><br><span class="line">  &quot;description&quot;: &quot;test 1.0&quot;,</span><br><span class="line">  &quot;main&quot;: &quot;index.js&quot;,</span><br><span class="line">  &quot;scripts&quot;: &#123;</span><br><span class="line">    &quot;start&quot;: &quot;webpack&quot; //把npm的start命令指向webpack命令</span><br><span class="line"></span><br><span class="line">  &#125;,</span><br><span class="line">  &quot;author&quot;: &quot;Anchen&quot;,</span><br><span class="line">  &quot;license&quot;: &quot;ISC&quot;,</span><br><span class="line">  &quot;devDependencies&quot;: &#123;</span><br><span class="line">    &quot;webpack&quot;: &quot;^1.13.3&quot;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>然后使用<code>npm start</code> 命令就可以，注意注释最后要去掉，否则会有一堆错误（亲测）。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;webpack有什么用&quot;&gt;&lt;a href=&quot;#webpack有什么用&quot; class=&quot;headerlink&quot; title=&quot;webpack有什么用&quot;&gt;&lt;/a&gt;webpack有什么用&lt;/h3&gt;&lt;p&gt;可以帮助我们把多个js文件打包为1个入口文件，并且可以按需加载。也就
      
    
    </summary>
    
    
      <category term="工作流" scheme="http://yoursite.com/tags/%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    
  </entry>
  
  <entry>
    <title>关于web渲染及硬件加速</title>
    <link href="http://yoursite.com/2016/08/31/%E5%85%B3%E4%BA%8Eweb%E6%B8%B2%E6%9F%93%E5%8F%8A%E7%A1%AC%E4%BB%B6%E5%8A%A0%E9%80%9F/"/>
    <id>http://yoursite.com/2016/08/31/关于web渲染及硬件加速/</id>
    <published>2016-08-31T10:03:56.000Z</published>
    <updated>2018-06-12T11:45:38.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。"><a href="#关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。" class="headerlink" title="关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。"></a>关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。</h3><p><strong>一.页面在浏览器上是怎么渲染的(以普通静态页面为例）</strong></p><p>浏览器首先获取html页面-&gt;分析这个页面（标签/属性/节点)-&gt;Dom结构-&gt;解析css-&gt;css+Dom每个节点的位置和大小等几何信息（layout)-&gt;css paint（绘制成位图）-&gt;传输到GPU渲染到屏幕（composited)。</p><p>reflow一步发生于layout，repaint是对应css paint这个步骤。</p><p>所以，在解析css开始的步骤，修改的css元素是在越前的步骤解析的话会越耗性能，因为它及其它后面的步骤将会被重新修改一遍。</p><p>换句话来说，Dom操作触发频繁reflow（layout）和repaint，layout发生在repaint之前，相对会造成更多性能损坏。</p><p>那么，哪些元素会影响layout、paint和composited？</p><p>举些我们很常用的例子：</p><p>影响layout：</p><p>margin/padding/width/height/display/border/top/left/right/bottom/position/font-size/text-align/line-height/font-weight/font-family/overflow…</p><p>影响repaint：</p><p>color/border-style/visibility/backgrounf/text-decoration/border-radius/outline/box-shadow/backgrounf-size…</p><p>注意：</p><p>【设置动画元素为absolute或fixed：</p><ul><li>position:static或position:relative元素应用动画效果会造成频繁的reflow。</li><li>position:absolute或position:fixed的元素应用动画效果只需要repaint.】</li></ul><p>关于以上括号内，出处应该是国外翻译为中文，很多文章都这么写，但经过测试和与朋友的讨论，发现这么说好像有问题。</p><p>如下为relative的渲染：</p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/relative.png" alt="png1"></p><p>如下为absolute的渲染:</p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/absolute.png" alt="png"></p><p>私以为，position:static或position:relative元素应用动画效果和position:absolute或position:fixed的元素应用动画效果都会造成它自己的元素触发这三个阶段，只是position:static或position:relative元素应用动画效果会造成文本流的其他元素reflow，而position:absolute或position:fixed的元素应用动画效果只会造成文本流其他元素repaint。</p><p>具体可看<a href="http://csstriggers.com/" target="_blank" rel="noopener">css查询</a></p><p><strong>二.硬件加速——把GPU利用起来</strong></p><p>GPU（图形处理器），是专为执行复杂的数学和几何计算而设计的，这些计算是图形渲染所必需的。通常CPU是双核四核，而GPU是上百成千，所以它的并发计算能力越强。偏移、放大缩小、旋转等这些操作都是矩阵变换，交给GPU完成，就会越快完成。</p><p>在GPU的众多特性之中，它可以存储一定数量的纹理（一个矩形的像素点集合）并且高效地操作这些纹理（比如进行特定的移动、缩放和旋转操作）。这些特性在实现一个<a href="http://ariya.ofilabs.com/2013/06/optimizing-css3-for-gpu-compositing.html" target="_blank" rel="noopener">流畅的动画</a>时特别有用。浏览器不会在动画的每一帧都绘制一次，而是生成DOM元素的快照，并作为GPU纹理（也被叫做层）存储起来。之后浏览器只需要告诉GPU去转换指定的纹理来实现DOM元素的动画效果。</p><p>而浏览器在进行硬件加速时，是根据css属性为元素生成layers，将layers作为texture从CPU上传到GPU，当改变layer的transform、opacity等属性时，渲染会跳过layout、paint这些步骤，直接通知layer做变换，即通过硬件加速，浏览器将需要硬件加速的元素放在一个新的复合层（composited layer）中渲染，跟主文档不是一个层中，所以可以跳过一些步骤加速生成位图绘制。</p><p>综上，简单总结就是，使用硬件加速一是可以减少CPU向GPU传输位图的时间，因为它只需绘制一次就作为GPU纹理存储起来；二是减少CPU进行layout和paint的时间。</p><p>现在，像Chrome, FireFox, Safari, IE9+和最新版本的Opera都支持硬件加速，当它们检测到页面中某个DOM元素应用了某些CSS规则时就会开启，最显著的特征的元素的3D变换。我们可以设置translate3d的值来告诉浏览器，另外，现在也可以使用will-change这个属性，它会告诉浏览器哪个属性未来即将改变，让浏览器自己来做优化。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">.animate&#123;</span><br><span class="line"></span><br><span class="line">    will-change:transform,opacity</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>除此之外，凡可以创建复合层（composited layer）规则的元素都可以开启硬件加速，列举如下：</p><ul><li><p>3D或透视变换的css属性（animation，transition师兄opacity，transform动画）</p></li><li><p>使用加速视频解码的元素</p></li><li><p>canvas</p></li><li><p>使用css filters的元素</p></li><li><p>元素有一个包含复合层的后代节点，那么此元素也将创建复合层</p></li><li><p>元素有一个z-index较低且包含一个复合层的兄弟元素（即该元素在复合层上面渲染）</p></li></ul><p><strong>三.硬件加速的探讨</strong></p><p>首先我们怎么查看一个页面是否启用了硬件加速，其实很简单。以chrome为例：</p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/QQ图片20150922112444.jpg" alt="jpg1"></p><p>可以看到页面蓝色框被分成一块一块，实际为浏览器渲染的位图，它绘制页面时只会绘制可视区域一定范围内的东西，而如果有黄色的框，则代表这个元素被放到特殊的复合层中渲染，即启用了GPU。</p><p>那么通过这个方式我们了解到复合层的数量，这是有意义的，因为连接CPU和GPU的总线带宽不是无限的，需要关注数据在CPU和GPU之间的传输，避免通道拥挤。所以回答第二点的最后一个问题，当页面上太多元素使用到3硬件加速时，反而会阻碍页面的加载，造成“卡顿”的现象。</p><p>在上面我们讨论到了创建复合层开启硬件加速的规则，最后两点（元素有一个包含复合层的后代节点，那么此元素也将创建复合层</p><p>以及元素有一个z-index较低且包含一个复合层的兄弟元素（即该元素在复合层上面渲染））其实往往会被忽略，造成许多不必要的元素也使用3d加速，比如下图：</p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/QQ图片20150922151018.png" alt="jpg2"> </p><p>这是我访问某一个页面较长的电商网站，发现页面上大量存在3d加速元素，但其实除了头部的轮播动画，并没有其余动画。经查询得知，头部动画运用到3d加速，但同时导致下面其他相对和绝对定位的元素都被放在复合层中。解决方法可以在头部轮播加上层级z-index，人为提升动画元素的z-index，让浏览器知道这个元素的层排序，就不会把其他z-index比它高的元素也弄到复合层中了，加上后页面如下：</p><p><img src="http://7xkluu.com1.z0.glb.clouddn.com/QQ图片20150922151130.png" alt="jpg3">.</p><p><strong>四.总结</strong></p><p>经过以上讨论，在前端web渲染上应尽量减少reflow和repaint。css动画可以适当开启3d（硬件）加速提升动画流畅性，但要注意使用方法，我们可以在动画上增加层级来告诉浏览器，避免不必要的GPU阻塞。</p><p>参考文献：</p><p><a href="http://mp.weixin.qq.com/s?__biz=MzA5NTM2MTEzNw==&amp;mid=379618526&amp;idx=1&amp;sn=bd7bc6f95f3344c3154a0e6868e7c100&amp;scene=1&amp;srcid=0922qh4Zi1QBJCS6qV5JdqzQ&amp;from=groupmessage&amp;isappinstalled=0#rd" target="_blank" rel="noopener">css硬件加速也有坑 ——张云龙</a></p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。&quot;&gt;&lt;a href=&quot;#关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括。&quot; class=&quot;headerlink&quot; title=&quot;关于web渲染性能，本文将分为循序渐进的几个部分进行总结概括
      
    
    </summary>
    
    
  </entry>
  
  <entry>
    <title>javascript对象和原型</title>
    <link href="http://yoursite.com/2016/06/04/javascript%E5%AF%B9%E8%B1%A1%E5%92%8C%E5%8E%9F%E5%9E%8B/"/>
    <id>http://yoursite.com/2016/06/04/javascript对象和原型/</id>
    <published>2016-06-04T13:46:28.000Z</published>
    <updated>2018-06-12T11:46:24.000Z</updated>
    
    <content type="html"><![CDATA[<h3 id="理解prototype"><a href="#理解prototype" class="headerlink" title="理解prototype"></a>理解prototype</h3><ul><li>C.pototype用于建立由new.C创建的对象的原型；</li><li>Object.getPrototypeOf(obj)是ES5中用来获取obj对象的原型对象的标准方法。</li></ul><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">User</span>(<span class="params">name,passwordHash</span>)</span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">this</span>.name = name;</span><br><span class="line"></span><br><span class="line"><span class="keyword">this</span>.passwordHash = passwordHash;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">User.prototype.toString = <span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">return</span> <span class="string">"[User"</span>+<span class="keyword">this</span>.name+<span class="string">"]"</span>;</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">User.prototype.checkPass = <span class="function"><span class="keyword">function</span>(<span class="params">password</span>)</span>&#123;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> u = <span class="keyword">new</span> User(<span class="string">'ss'</span>,<span class="string">'ssssss123456'</span>);</span><br></pre></td></tr></table></figure><p>我们给USer函数添加两个方法到User.prototypr对象中，当我们使用new操作符创建User的实例时，产生的对象u得到了自动分配的原型对象。</p><p>u.name和u.passwordHash返回的是对象u的直接属性当前值，如果没有找到，才会去接着找u的原型对象，即User.prototype中的方法。</p><p>构造函数的prototype属性用来设置原型，那检测原型可以这样做：</p><p>Object.getPrototypeOf(u) === USer.prototype;//true</p><h3 id="实例分析"><a href="#实例分析" class="headerlink" title="实例分析"></a>实例分析</h3><p>那么怎么运用呢？</p><p>最近写了一个抽奖小游戏</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">GiftsGame</span>(<span class="params">jTarget, lotteryCode</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.wrapp = jTarget;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.isWinner = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.tipMsg = <span class="string">""</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.responseCode = <span class="literal">null</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.isLogined = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.code = lotteryCode;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.lotteryPrize = [];</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.isGoing = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.hasChances = <span class="number">1</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.userLevel = <span class="number">0</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.isBegining = <span class="literal">true</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">this</span>.theEnd = <span class="literal">false</span>;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">var</span> _this = <span class="keyword">this</span>;</span><br><span class="line"></span><br><span class="line">     <span class="keyword">this</span>.init();</span><br><span class="line"></span><br><span class="line">   </span><br><span class="line"></span><br><span class="line">     _this.cookieValue = <span class="string">""</span>;</span><br><span class="line"></span><br><span class="line">&#125; <span class="comment">// GitGame函数保存一系列变量</span></span><br></pre></td></tr></table></figure><p>以更新用户中奖名单的功能来说，通过建立原型方式调用：</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line">GiftsGame.prototype.updateWinner = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="keyword">var</span> _this = <span class="keyword">this</span>;</span><br><span class="line"></span><br><span class="line">        setTimeout(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">            &#125;);</span><br><span class="line"></span><br><span class="line">        &#125;, <span class="number">1</span>);</span><br><span class="line"></span><br><span class="line">            <span class="comment">/**</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">             * 混淆用户pin</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">             */</span></span><br><span class="line"></span><br><span class="line">       <span class="function"><span class="keyword">function</span> <span class="title">confusePin</span>(<span class="params">pin</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">       &#125;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">         * 滚动显示获奖信息</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">         * @param wrapper</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">         * @param time</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">function</span> <span class="title">autoScorll</span>(<span class="params">wrapper, winnerLen</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line">     &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure><p>这种方法有什么好处呢，我是这么理解的，对于这个抽奖小游戏，大主体就是这个GiftsGame，实际上可以看成只有这个函数，下面都是这个函数的各个功能，这样的话就很有归纳和继承性，并且不会影响除这个游戏外的抽蛋小游戏和抓鸡小游戏的东西。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h3 id=&quot;理解prototype&quot;&gt;&lt;a href=&quot;#理解prototype&quot; class=&quot;headerlink&quot; title=&quot;理解prototype&quot;&gt;&lt;/a&gt;理解prototype&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;C.pototype用于建立由new.C创建的对象的原型
      
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://yoursite.com/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>Bootstrape js之transition</title>
    <link href="http://yoursite.com/2016/05/01/Bootstrape-js%E4%B9%8Btransition/"/>
    <id>http://yoursite.com/2016/05/01/Bootstrape-js之transition/</id>
    <published>2016-05-01T05:12:43.000Z</published>
    <updated>2018-06-12T11:42:26.000Z</updated>
    
    <content type="html"><![CDATA[<h2 id="transitionend函数"><a href="#transitionend函数" class="headerlink" title="transitionend函数"></a>transitionend函数</h2><h3 id="一-js中的transitionend事件"><a href="#一-js中的transitionend事件" class="headerlink" title="一.js中的transitionend事件"></a>一.js中的transitionend事件</h3><p>首先JavaScript有一个transitionend事件，在css完成过渡后触发。</p><p>与css3的transition一样，需要加浏览器前缀：webkitTransitionEnd(chrome/safari3.1-6.0)、mozTransitionEnd(Firfox)、oTransitionEnd(opera)/transitionend(IE9+)。</p><p>栗子：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">demo.addEventListener(&apos;webkitTransitionEnd&apos;,function()&#123;</span><br><span class="line"></span><br><span class="line">    ...</span><br><span class="line"></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><strong>注意：addEventListener（）方法是ie8及以下浏览器不支持。</strong></p><p>同时，transition动画是不具有start的事件，只有transitionEnd事件。</p><p>但是animation动画有animationend、animationiteration、animationstart三个事件，分别对应动画结束播放触发、动画重复播放触发和动画开始播放触发。</p><p>这些事件都是用<code>element.addEventListener(&#39;事件&#39;,end,false)</code>来捕捉。</p><p>animationend和transitionend有一个明显的区别是：animationend会在元素的整个动画执行完毕再触发，而transitionend会每一个样式属性值改变一次状态触发一次，不同的属性值改变会累计触发，</p><p>比如下面的例子，webkitAnimationEnd事件只在元素向右移动,然后向左返回之后触发一次,而webkitTransitionEnd事件将在元素向右移动之后触发一次,在元素向左返回之后再触发一次。</p><p><a href="http://anchen1204.github.io/demo/transitionend.html" target="_blank" rel="noopener">栗子</a></p><p>以上为js的总结，接下来继续bootstrape。</p><h3 id="二-bootstrape的transition"><a href="#二-bootstrape的transition" class="headerlink" title="二.bootstrape的transition"></a>二.bootstrape的transition</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br></pre></td><td class="code"><pre><span class="line">+function ($) &#123;</span><br><span class="line"></span><br><span class="line">  &apos;use strict&apos;;</span><br><span class="line"></span><br><span class="line">  // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)</span><br><span class="line"></span><br><span class="line">  // ============================================================</span><br><span class="line"></span><br><span class="line">  function transitionEnd() &#123;</span><br><span class="line"></span><br><span class="line">    var el = document.createElement(&apos;bootstrap&apos;);</span><br><span class="line"></span><br><span class="line">    var transEndEventNames = &#123;</span><br><span class="line"></span><br><span class="line">      WebkitTransition : &apos;webkitTransitionEnd&apos;,</span><br><span class="line"></span><br><span class="line">      MozTransition    : &apos;transitionend&apos;,</span><br><span class="line"></span><br><span class="line">      OTransition      : &apos;oTransitionEnd otransitionend&apos;,</span><br><span class="line"></span><br><span class="line">      transition       : &apos;transitionend&apos;</span><br><span class="line"></span><br><span class="line">    &#125;//把所有浏览器前缀整合为一个对象</span><br><span class="line"></span><br><span class="line">    for (var name in transEndEventNames) &#123;</span><br><span class="line"></span><br><span class="line">      if (el.style[name] !== undefined) &#123;</span><br><span class="line"></span><br><span class="line">        return &#123; end: transEndEventNames[name] &#125;</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;//for遍历前缀，判断css属性是否存在</span><br><span class="line"></span><br><span class="line">    return false // explicit for ie8 (  ._.)，若不存在css属性则返回，此时可添加回调函数</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  $.fn.emulateTransitionEnd = function (duration) &#123;</span><br><span class="line"></span><br><span class="line">    var called = false;//transitionend时间是否已经触发的标识</span><br><span class="line"></span><br><span class="line">    var $el = this</span><br><span class="line"></span><br><span class="line">    $(this).one(&apos;bsTransitionEnd&apos;, function () &#123; called = true &#125;)//true为已经触发</span><br><span class="line"></span><br><span class="line">    var callback = function () &#123;</span><br><span class="line"></span><br><span class="line"> if (!called) (el).trigger($.support.transition.end) &#125;//未触发，强制触发</span><br><span class="line"></span><br><span class="line">    setTimeout(callback, duration)//一段时间后检测是否触发，因为有时属性值没有发生改变并不会触发，但是在页面过程中可能后来会执行，确保每次回调都被调用需要使用定时器</span><br><span class="line"></span><br><span class="line">    return this</span><br><span class="line"></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  $(function () &#123;</span><br><span class="line"></span><br><span class="line">    $.support.transition = transitionEnd()</span><br><span class="line"></span><br><span class="line">    if (!$.support.transition) return</span><br><span class="line"></span><br><span class="line">    $.event.special.bsTransitionEnd = &#123;</span><br><span class="line"></span><br><span class="line">      bindType: $.support.transition.end,</span><br><span class="line"></span><br><span class="line">      delegateType: $.support.transition.end,</span><br><span class="line"></span><br><span class="line">      handle: function (e) &#123;</span><br><span class="line"></span><br><span class="line">        if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">  &#125;)//自定义事件，添加事件回调可以这样element.one(&apos;bsTransitionEnd&apos;,function()&#123;&#125;).emulateTransitionEnd(1000);</span><br><span class="line"></span><br><span class="line">&#125;(jQuery);</span><br></pre></td></tr></table></figure><p>以上为原版代码。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;h2 id=&quot;transitionend函数&quot;&gt;&lt;a href=&quot;#transitionend函数&quot; class=&quot;headerlink&quot; title=&quot;transitionend函数&quot;&gt;&lt;/a&gt;transitionend函数&lt;/h2&gt;&lt;h3 id=&quot;一-js中的transit
      
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://yoursite.com/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>rem+sass移动端自适应</title>
    <link href="http://yoursite.com/2016/03/29/rem-sass%E7%A7%BB%E5%8A%A8%E7%AB%AF%E8%87%AA%E9%80%82%E5%BA%94/"/>
    <id>http://yoursite.com/2016/03/29/rem-sass移动端自适应/</id>
    <published>2016-03-29T12:35:24.000Z</published>
    <updated>2018-06-12T11:46:52.000Z</updated>
    
    <content type="html"><![CDATA[<p> 首先说一个不离题的题外话，上周末的时候在公司加班，是一个移动端的活动页，遇到一个问题。</p><p> 页面一开始采用是这一段：</p><p><a href="https://github.com/re54k/mobileweb-utilities/blob/master/util/mobile-util.js" target="_blank" rel="noopener">同事扒来的</a>,总之原理是改变meta标签里的intial-scale来进行整个画布的缩放。</p><p>之前有两个项目都用过适用，所以我也没多想就直接加上去了。</p><p>其实还是各种美好，知道遇到了升级版本为9.3的iphone中的微信内置浏览器，当intial-scale不是1，滑屏时会整个页面左右移动。然后我正好有一个左右移动的类轮播，于是体验就不好了。最后查到是intial-scale的问题后，果断放弃这一大段代码，重新加了几句调整html的根字体大小：</p><p>但是淘宝其实采用的就是以上做法，并没有出现上述问题，记在这里，后续研究更新。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">&lt;script&gt;</span><br><span class="line"></span><br><span class="line">      //重置html字体大小</span><br><span class="line"></span><br><span class="line">      var _resize = function()&#123;</span><br><span class="line"></span><br><span class="line">        var html = document.documentElement,</span><br><span class="line"></span><br><span class="line">          w = html.clientWidth/640, w =16*w;</span><br><span class="line"></span><br><span class="line">        html.setAttribute(&apos;style&apos;, &apos;font-size:&apos; + w + &apos;px&apos;);</span><br><span class="line"></span><br><span class="line">      &#125;</span><br><span class="line"></span><br><span class="line">      _resize();</span><br><span class="line"></span><br><span class="line">      window.addEventListener(&apos;resize&apos;, _resize);</span><br><span class="line"></span><br><span class="line">&lt;/script&gt;</span><br></pre></td></tr></table></figure><p>这样的目的其实一样达到了，而且微信也美好了。</p><p>sass只需要设置:</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">$fontRem: 16px;</span><br><span class="line"></span><br><span class="line">@function rem($px) &#123; @return $px / $fontRem * 1rem; &#125;</span><br></pre></td></tr></table></figure><p>就可以很方便的使用啦。</p><p>好了，说完入场就可以进入正题，开始总结啦~</p><h3 id="1-为什么用rem"><a href="#1-为什么用rem" class="headerlink" title="1.为什么用rem"></a>1.为什么用rem</h3><p>rem就是一个相对于根元素的字体大小的单位，还有一个跟它挺像的em，em是相对于父元素字体大小的单位，所以，一个页面根元素的字体大小是固定的，但是每一个元素它的父元素字体大小却不一定都一样，因此更推荐使用rem。</p><p>所以，改变html的根元素大小，整个页面的尺寸也会相应的改变，那么我们根据屏幕尺寸和html根元素比例，就可以做到适应屏幕的大小了。</p><p>那么这个比例怎么算的，这就要看设计稿了，加入设计稿是640px，那么遇到640px的屏幕宽，比例就是1…以此类推</p><p>所以上面的js其实就是动态来根据比例设置根元素的字体大小，默认设计稿为640，比例为<code>w = html.clientWidth/640;</code>,然后定一个基数，为16px，所有有<code>w=16*w;html.setAttribute(&#39;style&#39;, &#39;font-size:&#39; + w + &#39;px&#39;);</code></p><h3 id="2-所有单位需统一"><a href="#2-所有单位需统一" class="headerlink" title="2.所有单位需统一"></a>2.所有单位需统一</h3><p>有一个bug是，某次设置了一个块级元素的height：4rem；然后没有设置宽度，那么宽度就是默认的100%。</p><p>这样的话实际缩放是没有等比例缩放的，在某些分辨率下会出现错位。所以使用rem缩放的话，一定要记得宽高都需要设置好。</p><p>贴一个自己最近做的项目例子吧:<a href="[http://m.jd.ru/channel/smartphone.html](http://m.jd.ru/channel/smartphone.html]">smartphoneM端频道页</a>)</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt; 首先说一个不离题的题外话，上周末的时候在公司加班，是一个移动端的活动页，遇到一个问题。&lt;/p&gt;
&lt;p&gt; 页面一开始采用是这一段：&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/re54k/mobileweb-utilities/blob/maste
      
    
    </summary>
    
    
      <category term="css" scheme="http://yoursite.com/tags/css/"/>
    
  </entry>
  
  <entry>
    <title>一分钟学会ajax调用</title>
    <link href="http://yoursite.com/2016/02/12/%E4%B8%80%E5%88%86%E9%92%9F%E5%AD%A6%E4%BC%9Aajax%E8%B0%83%E7%94%A8/"/>
    <id>http://yoursite.com/2016/02/12/一分钟学会ajax调用/</id>
    <published>2016-02-12T11:38:44.000Z</published>
    <updated>2018-06-12T11:47:10.000Z</updated>
    
    <content type="html"><![CDATA[<p>怎么写ajax，之前也不是很懂，后来在项目中接触几次后也就差不多了。</p><p>首先来个场景，有一个页面的价格需要调用ajax的接口来拉取，拉取的原理是，每个商品的商品id发给后台对应拉到每个商品的价格然后填写。</p><p>于是我定义了一个Prize的函数：function Prize() {}。</p><p><strong>然后首先第一步，取到每个商品的id并且拼在一起一次性请求：</strong>（这个怎么拼看ajax的发送规则，比如这个例子是商品id,使用”,”分割）</p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">var</span> _value = <span class="string">""</span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> selector = $(<span class="string">'.list li'</span>);</span><br><span class="line"></span><br><span class="line">selector.each(<span class="function"><span class="keyword">function</span>(<span class="params">_idx</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (_idx == <span class="number">0</span>) &#123;</span><br><span class="line"></span><br><span class="line">_value = $(<span class="keyword">this</span>).attr(<span class="string">'skuid'</span>);</span><br><span class="line"></span><br><span class="line">&#125; <span class="keyword">else</span> &#123;</span><br><span class="line"></span><br><span class="line">_value = _value + <span class="string">','</span> + $(<span class="keyword">this</span>).attr(<span class="string">'skuid'</span>);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">value = $.trim(value);</span><br><span class="line"></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><strong>第二步就是发送ajax请求并返回得到的价格：</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line">$.ajax(&#123;</span><br><span class="line"></span><br><span class="line">type: <span class="string">'GET'</span>,</span><br><span class="line"></span><br><span class="line">url: <span class="string">'ajax地址'</span>,</span><br><span class="line"></span><br><span class="line">data: &#123;</span><br><span class="line"></span><br><span class="line"><span class="string">'skuIds'</span>: _value</span><br><span class="line"></span><br><span class="line">&#125;,</span><br><span class="line"></span><br><span class="line">dataType: <span class="string">'jsonp'</span>,</span><br><span class="line"></span><br><span class="line">success: <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(data)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p><strong>第三步就是请求成功后对页面的输出，success里的函数就是写成功后要做的事：</strong></p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br></pre></td><td class="code"><pre><span class="line">success: <span class="function"><span class="keyword">function</span>(<span class="params">data</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="built_in">console</span>.log(data)</span><br><span class="line"></span><br><span class="line">selector.each(<span class="function"><span class="keyword">function</span>(<span class="params">_index</span>) </span>&#123;</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> sku = .trim((<span class="keyword">this</span>).attr(<span class="string">'skuid'</span>));</span><br><span class="line"></span><br><span class="line"><span class="keyword">for</span> (<span class="keyword">var</span> i = <span class="number">0</span>; i &lt; data.data.length; i++) &#123;</span><br><span class="line"> <span class="comment">//for循环是遍历每一个商品id，然后if语句中要多一步验证返回的商品id和当前的id是不是同一个，如果是则写入价格， data.data[i].Price的Prize是因为返回字段的定义，有Prize字段存储，具体看ajax返回的内容进行程序编写。</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> eachData = data.data[i];</span><br><span class="line"></span><br><span class="line"><span class="keyword">var</span> eachprice = data.data[i].Price;</span><br><span class="line"></span><br><span class="line"><span class="keyword">if</span> (sku == eachData.skuId) &#123;</span><br><span class="line"></span><br><span class="line">(<span class="keyword">this</span>).find(<span class="string">'.price  .price-cur'</span>).html(<span class="string">""</span> + eachprice);</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">&#125;)</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="顺便说下each方法和-each-函数，我最喜欢用例子来理解了："><a href="#顺便说下each方法和-each-函数，我最喜欢用例子来理解了：" class="headerlink" title="顺便说下each方法和$.each()函数，我最喜欢用例子来理解了："></a>顺便说下each方法和$.each()函数，我最喜欢用例子来理解了：</h3><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$(<span class="string">'.tag'</span>).each(<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>($(item).find(<span class="string">'span'</span>).text()!=<span class="string">''</span>)&#123;</span><br><span class="line">        $(item).show()<span class="string">'</span></span><br><span class="line"><span class="string">    &#125;</span></span><br><span class="line"><span class="string">&#125;)</span></span><br></pre></td></tr></table></figure><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">$.each($(<span class="string">'.tag-discount'</span>),<span class="function"><span class="keyword">function</span>(<span class="params">index,item</span>)</span>&#123;</span><br><span class="line">    <span class="keyword">if</span>($(item).find()<span class="string">'span'</span>.text()!=<span class="string">''</span>)&#123;</span><br><span class="line">        $(item).show();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure><p>这两个的效果一样，但是$.each()函数不同于JQuery对象的each()方法，它是一个全局函数，不操作JQuery对象，把对象作为第一个参数，以一个回调函数作为第二个参数：第一个为对象成员或者数组索引，第二个为对应变量或者内容。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;怎么写ajax，之前也不是很懂，后来在项目中接触几次后也就差不多了。&lt;/p&gt;
&lt;p&gt;首先来个场景，有一个页面的价格需要调用ajax的接口来拉取，拉取的原理是，每个商品的商品id发给后台对应拉到每个商品的价格然后填写。&lt;/p&gt;
&lt;p&gt;于是我定义了一个Prize的函数：func
      
    
    </summary>
    
    
      <category term="ajax" scheme="http://yoursite.com/tags/ajax/"/>
    
  </entry>
  
  <entry>
    <title>jQuery中的事件绑定/委托</title>
    <link href="http://yoursite.com/2016/01/07/jQuery%E4%B8%AD%E7%9A%84%E4%BA%8B%E4%BB%B6%E7%BB%91%E5%AE%9A-%E5%A7%94%E6%89%98/"/>
    <id>http://yoursite.com/2016/01/07/jQuery中的事件绑定-委托/</id>
    <published>2016-01-07T03:32:19.000Z</published>
    <updated>2018-06-12T11:47:34.000Z</updated>
    
    <content type="html"><![CDATA[<p>jQuery的事件委托和绑定其实是一个非常重要的内容，之前可能用on或者bind比较多，但最近做页面发现其实应该把这些东西总结一下，根据情况选择最恰当的方式。</p><p>主要探讨的是以下事件：delegate()、bind()、on()通过例子和对比来加深印象。</p><h3 id="bind"><a href="#bind" class="headerlink" title="bind()"></a>bind()</h3><p><code>$(&#39;a&#39;).bind(&#39;click&#39;,function(){alert(&quot;ok&quot;);})</code>  </p><p>其实可以简写为：</p><p><code>$(&#39;a&#39;).click(function(){alert(&quot;ok&quot;);})</code></p><p>这样就好懂多了吧。</p><p>bind有两个问题：</p><p>1.当匹配的元素过多，比如页面有40个a标签，就得执行40次绑定，影响性能；</p><p>2.对于页面上还未存在的元素，就算动态添加后，是无法执行这个绑定事件的。</p><p>而delegate()恰好可以解决这两个问题。</p><h3 id="elegate"><a href="#elegate" class="headerlink" title="elegate()"></a>elegate()</h3><p><code>$(*selector*).delegate(*childSelector*,*event*,*data*,*function*)</code></p><p>delegate()方法为指定的元素（属于被选元素的子元素）添加一个或多个事件处理，使用这个方法的事件处理程序适用于当前或未来的元素。</p><p>这是怎么理解呢？对比一下bind：</p><p><code>$(&#39;a&#39;).bind(&#39;click&#39;,function(){alert(&quot;ok&quot;);})</code></p><p>这是bind的用法，给页面的a元素绑定一个点击事件，点击后弹出内容。</p><p>那么用delegate是这样的：</p><p><code>$(document).delegate(&#39;a&#39;, &#39;click&#39;, function() { alert(&#39;ok;)});</code></p><p><strong>bind直接将方法绑定到独立的元素上，但它不能将方法绑定到一个暂时还未出现的元素上</strong>。而<strong>delegate方法是将事件方法绑定到一个需要作用的元素它的父元素上，那么这个元素是否已经存在都可以被处理</strong>。</p><p>另外，将一个方法绑定到一个或者一组父元素比直接为页面上的每个元素（特别是数量很多的情况下）绑定方法无疑更有效率。</p><h3 id="on"><a href="#on" class="headerlink" title="on()"></a>on()</h3><p>live()方法在jq1.9版本已经被删除，用on来代替。</p><p>之前我们这么写：</p><p><code>$(&#39;a&#39;).live(&#39;click&#39;,function(){alert(&quot;ok&quot;);})</code></p><p>现在用on需要这么写</p><p><code>$(document ).on(&#39;click&#39;,&#39;a&#39;,function(){alert(&quot;ok&quot;)})</code></p><p>再解释一遍，我的页面有一个id为a的div，我将要在它里面动态添加一个class为b的子元素，然后给这个b绑定一个事件，我需要这么写：</p><p><code>$(&#39;#a&#39;).on(&#39;click&#39;,&#39;.b&#39;,function(){}）</code></p><p>是不是跟delegate()很像…</p><p>它也可以这么使用：</p><p><code>$(&#39;a&#39;).bind(&#39;click&#39;,function(){alert(&quot;ok&quot;);})</code></p><p>==</p><p><code>$(&#39;a&#39;).on(&#39;click&#39;,function(){alert(&quot;ok&quot;);})</code></p><p>也就是说on()方法可以替代live()，可以替代delegate(),也可以替代bind().</p><p>综上，on()是最为推荐的方法。但是根据情况仍然可以选择其他适合的替代写法。</p><p>除此之外，如需溢出事件绑定，可以用off()方法：</p><p><code>$(&#39;a&#39;).off(&#39;click&#39;)</code></p><p>添加只运行一次的事件然后移除，可使用one()方法。</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;jQuery的事件委托和绑定其实是一个非常重要的内容，之前可能用on或者bind比较多，但最近做页面发现其实应该把这些东西总结一下，根据情况选择最恰当的方式。&lt;/p&gt;
&lt;p&gt;主要探讨的是以下事件：delegate()、bind()、on()通过例子和对比来加深印象。&lt;/p&gt;
      
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://yoursite.com/tags/JavaScript/"/>
    
  </entry>
  
  <entry>
    <title>JS apply和call方法</title>
    <link href="http://yoursite.com/2015/10/22/JS-apply%E5%92%8Ccall%E6%96%B9%E6%B3%95/"/>
    <id>http://yoursite.com/2015/10/22/JS-apply和call方法/</id>
    <published>2015-10-22T10:08:32.000Z</published>
    <updated>2018-07-29T14:16:28.000Z</updated>
    
    <content type="html"><![CDATA[<p>这几天重新翻了遍  <a href="http://bonsaiden.github.io/JavaScript-Garden/zh/#function.arguments" target="_blank" rel="noopener">js秘密花园</a>。 讲到之前忽略的call和apply方法，觉得有必要整理一下。</p><p>w3cschool的例子解释：</p><p>call()方法的第一个参数用作this的对象，其他参数都直接传递给函数本身。</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">function sayColor(sPrefix,sSuffix) &#123;</span><br><span class="line"></span><br><span class="line">    alert(sPrefix + this.color + sSuffix);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">var obj = new Object();</span><br><span class="line"></span><br><span class="line">obj.color = &quot;blue&quot;;</span><br><span class="line"></span><br><span class="line">sayColor.call(obj, &quot;The color is &quot;, &quot;a very nice color indeed.&quot;);</span><br></pre></td></tr></table></figure><ul><li>对象obj的color属性等于blue；</li><li>调用call()方法时，第一个参数是obj，即赋予sayColor()函数的this关键字值是obj.</li><li>第二个和第三个参数是字符串，与sayColor()函数中的参数sPrefix和sSuffix匹配；</li></ul><p>apply()方法有两个参数，用作this的对象和要传递给函数的参数的数组</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line">function sayColor(sPrefix,sSuffix) &#123;</span><br><span class="line"></span><br><span class="line">    alert(sPrefix + this.color + sSuffix);</span><br><span class="line"></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">var obj = new Object();</span><br><span class="line"></span><br><span class="line">obj.color = &quot;blue&quot;;</span><br><span class="line"></span><br><span class="line">sayColor.apply(obj, new Array(&quot;The color is &quot;, &quot;a very nice color indeed.&quot;));</span><br></pre></td></tr></table></figure><ul><li>调用apply()方法时，第一个参数仍是obj，即sayColor()函数中的this值是obj；</li><li>第二个参数则与sayColor()对应参数相匹配；</li></ul><p>结合这两个例子，其实就可以明白call与apply就是为了改变对象的this。它们的第一个参数都是要传入给当前对象的对象（this），后面的参数都是传递给当前对象的参数。比如方法里写了this，普通调用这个方法这个this的可能是window，而如果用call，第一个参数写啥，this就是啥。</p><p>再举一个例子更浅显地说明它们的作用：</p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">function People()&#123;&#125;</span><br><span class="line"></span><br><span class="line">   People.prototype=&#123;</span><br><span class="line"></span><br><span class="line">   age:&quot;22&quot;,</span><br><span class="line"></span><br><span class="line">   card:function()&#123;</span><br><span class="line"></span><br><span class="line">     console.log(&quot;I am &quot;+this.age);</span><br><span class="line"></span><br><span class="line">   &#125;</span><br><span class="line"></span><br><span class="line">&#125; </span><br><span class="line"></span><br><span class="line">var xiaoming = new People();</span><br><span class="line"></span><br><span class="line">xiaoming.card();</span><br></pre></td></tr></table></figure><p>现在我们有另外一个人xiaohong={age:”20”}。可以直接用call或apply：</p><p><code>xiaoming.card.call(xiaohong)</code></p><p>这样我就不需要重新定义xiaohong了。</p><p>那么call和apply有什么区别呢，其实只在于两个函数接受的参数形式不同。</p><p>Function.apply(obj,args)方法能接受两个参数：obj这个对象将代替Function类的this对象；args讲作为参数传递给Function。</p><p>Function.call(obj,[arg1,arg2..])：obj这个对象将代替Function类的this对象；[arg1,arg2..]：这个是一个参数列表。</p><p>总而言之，即是apply传入的是一个参数数组，即将多个参数组合成为一个数组传入，而call则作为call的参数传入。func.call(func1,var1,var2,var3)对应的apply写法为：func.apply(func1,[var1,var2,var3])</p>]]></content>
    
    <summary type="html">
    
      
      
        &lt;p&gt;这几天重新翻了遍  &lt;a href=&quot;http://bonsaiden.github.io/JavaScript-Garden/zh/#function.arguments&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;js秘密花园&lt;/a&gt;。 讲到之前忽略
      
    
    </summary>
    
    
      <category term="JavaScript" scheme="http://yoursite.com/tags/JavaScript/"/>
    
  </entry>
  
</feed>
